rm(list = ls())

Dependencies

Packages included:

  • tidyverse - for convenient code flow, data wrangling and plotting
  • rjags & R2jags - to link JAGS and R
  • skimr - for data summary
  • corrr - to output correlation matrices in dataframe format
  • cowplot & patchwork - to combine plot panels
  • Rmarkdown - to produce this neat little documentation
# load pacman package from the repository, if you do not already have it
if (!require('pacman')) install.packages('pacman', repos="https://cloud.r-project.org")
pacman::p_load(tidyverse, # set of packages for data manipulation, exploration and visualisation
               rjags,     # to link JAGS and R
               R2jags,    # to link JAGS and R
               skimr,     # for quick dataframe inspection
               corrr,     # output correlation matrices as data frame
               cowplot,   # combine plot panels
               patchwork, # -"-
               rmarkdown) # for R Markdown formatting

Functions used:

  • predictor x species cover plot grid function
  • effect size plot function
# cover plot grids ----
pred.plot.grid <- function(df){
  
  taxa <- df %>% pull(taxon) %>% unique() %>% as.character()
  
  for(taxon_nr in 1:length(taxa)){
    plot <- ggplot(data = df %>% filter(taxon == taxa[taxon_nr]), 
                   aes(y = cover, group = taxon)) +
      geom_point(aes(x = pred_value), colour = "darkgrey") +
      geom_smooth(aes(x = pred_value), method = "lm", colour = "darkgreen", se = TRUE, na.rm = TRUE) +
      geom_smooth(aes(x = pred_value), method = "lm", formula = y ~ poly(x, 2), colour = "darkorange", se = TRUE, na.rm = TRUE) +
      facet_wrap(~predictor, scales = "free", ncol = 4) +
      scale_y_continuous("relative no. pin hits per plot",
                         limits = c(0, max(df %>% 
                                             filter(taxon == taxa[taxon_nr]) %>% 
                                             pull(cover)))) +
      labs(x = "predictor value") +
      ggtitle(paste0(taxa[taxon_nr], " cover ~ predictors")) +
      theme_bw() +
      theme(legend.position = "none")
    print(plot)
  }
}

# effect size plots ----
# for cases with only 'significant' effects
model_plot_sig_function <- function(model_coeff_output, title_string, plot_width) {
  target_vars <- c("b.tempjja.x", "b.tempjja.x2",
                   "b.tempcont.x", "b.tempcont.x2",
                   "b.precipjja.x", "b.precipjja.x2",
                   "b.sri",
                   "b.tri",
                   "b.twi", 
                   "b.compet")
  solutions <- model_coeff_output
  names(solutions) <- c("variable", "post.mean", "post.sd", "l95", "l90", "u90", "u95", "Rhat")
  solutions <- solutions %>% 
    filter(variable %in% target_vars)
  # solutions$variable <- factor(solutions$variable,
  #                               levels = c("b.tempjja.x", "b.tempjja.x2",
  #                                          "b.tempcont.x", "b.tempcont.x2",
  #                                          "b.precipjja.x", "b.precipjja.x2",
  #                                          "b.sri",
  #                                          "b.tri",
  #                                          "b.twi",
  #                                          "b.compet"))
  min_value <- floor(min(solutions$l95))
  max_value <- ceiling(max(solutions$u95))
  solutions$sig <- "ns"
  solutions$sig[solutions$l95 < 0 & solutions$u95 < 0] <- "sig"
  solutions$sig[solutions$l95 > 0 & solutions$u95 > 0] <- "sig"
  label_colour <- rep("black", nrow(solutions))
  label_colour[solutions$sig == "sig"] <- theme_darkgreen
  label_face <- rep("plain", nrow(solutions))
  label_face[solutions$sig == "sig"] <- "bold"
  # label_face[response == "T1_mean" & solutions$sig == "sig"] <- "bold"
  title_string <- title_string
  title_colour <- "grey10"
  # if(response == "T1_mean" | response == "T1_amp") title_colour <- theme_red
  # if(response == "T2_mean" | response == "T2_amp") title_colour <- theme_yellow
  # if(response == "T1_mean") response <- "Soil"
  # if(response == "T2_mean") response <- "Ground"
  
  
  model_plot_sig <- ggplot(solutions, aes(x = variable, y = post.mean,
                                      ymin = l95, ymax = u95,
                                      colour = sig)) +
    geom_point() +
    geom_errorbar(width = .8) +
    theme_cowplot(18) +
    ylab("Effect Size (scaled)") +
    xlab("") +
    ggtitle(paste0(title_string)) +
    scale_colour_manual(values = c("black", theme_darkgreen)) +
    scale_y_continuous(limits = c(min_value, max_value), breaks = seq(min_value,max_value,0.5)) +
    # scale_x_discrete(limits = c("b.tempjja.x", "b.tempjja.x2",
    #         "b.tempcont.x", "b.tempcont.x2",
    #         "b.precipjja.x", "b.precipjja.x2",
    #         "b.sri",
    #         "b.tri",
    #         "b.twi",
    #         "b.compet"),
    #                  labels = c("summer temperature", bquote(.("summer") *" "* temperature^2),
    #                             "temperature variability", bquote(.("temperature") *" "* variability^2),
    #                             "summer precipitation", bquote(.("summer") *" "* precipitation^2),
    #                             "solar radiation",
  #                             "terrain ruggedness",
  #                             "moisture availability",
  #                             "competition")) +
  annotate("segment", x = 0, xend = plot_width, y = 0, yend = 0) +
    theme(axis.text.x = element_text(angle = 45, hjust = 1, colour = label_colour, face = label_face),
          plot.title = element_text(colour = title_colour, face = "italic"),
          legend.position = "none")
  return(model_plot_sig)
}

# for cases with marginal 'significance'
model_plot_marg_function <- function(model_coeff_output, title_string, plot_width) {
  target_vars <- c("b.tempjja.x", "b.tempjja.x2",
                   "b.tempcont.x", "b.tempcont.x2",
                   "b.precipjja.x", "b.precipjja.x2",
                   "b.sri",
                   "b.tri",
                   "b.twi", 
                   "b.compet")
  solutions <- model_coeff_output
  names(solutions) <- c("variable", "post.mean", "post.sd", "l95", "l90", "u90", "u95", "Rhat")
  solutions <- solutions %>% 
    filter(variable %in% target_vars)
  # solutions$variable <- factor(solutions$variable,
  #                               levels = c("b.tempjja.x", "b.tempjja.x2",
  #                                          "b.tempcont.x", "b.tempcont.x2",
  #                                          "b.precipjja.x", "b.precipjja.x2",
  #                                          "b.sri",
  #                                          "b.tri",
  #                                          "b.twi",
  #                                          "b.compet"))
  min_value <- floor(min(solutions$l95))
  max_value <- ceiling(max(solutions$u95))
  solutions$sig <- "ns"
  solutions$sig[solutions$l95 < 0 & solutions$u95 < 0] <- "sig"
  solutions$sig[solutions$l95 > 0 & solutions$u95 > 0] <- "sig"
  solutions$sig[solutions$l90 < 0 & solutions$u90 < 0 & solutions$l95 < 0 & solutions$u95 > 0] <- "marg"
  solutions$sig[solutions$l90 > 0 & solutions$u90 > 0 & solutions$l95 < 0 & solutions$u95 > 0] <- "marg"
  label_colour <- rep("black", nrow(solutions))
  label_colour[solutions$sig == "sig"] <- theme_darkgreen
  label_colour[solutions$sig == "marg"] <- theme_purple
  label_face <- rep("plain", nrow(solutions))
  label_face[solutions$sig == "sig"] <- "bold"
  # label_face[response == "T1_mean" & solutions$sig == "sig"] <- "bold"
  title_string <- title_string
  title_colour <- "grey10"
  # if(response == "T1_mean" | response == "T1_amp") title_colour <- theme_red
  # if(response == "T2_mean" | response == "T2_amp") title_colour <- theme_yellow
  # if(response == "T1_mean") response <- "Soil"
  # if(response == "T2_mean") response <- "Ground"
  
  
  model_plot_marg <- ggplot(solutions, aes(x = variable, y = post.mean,
                                      ymin = l95, ymax = u95,
                                      colour = sig)) +
    geom_point() +
    geom_errorbar(width = .8) +
    theme_cowplot(18) +
    ylab("Effect Size (scaled)") +
    xlab("") +
    ggtitle(paste0(title_string)) + 
    scale_colour_manual(values = c(theme_purple, "black", theme_darkgreen)) +
    scale_y_continuous(limits = c(min_value, max_value), breaks = seq(min_value,max_value,0.5)) +
    # scale_x_discrete(limits = c("b.tempjja.x", "b.tempjja.x2",
    #         "b.tempcont.x", "b.tempcont.x2",
    #         "b.precipjja.x", "b.precipjja.x2",
    #         "b.sri",
    #         "b.tri",
    #         "b.twi",
    #         "b.compet"),
    #                  labels = c("summer temperature", bquote(.("summer") *" "* temperature^2),
    #                             "temperature variability", bquote(.("temperature") *" "* variability^2),
    #                             "summer precipitation", bquote(.("summer") *" "* precipitation^2),
    #                             "solar radiation",
  #                             "terrain ruggedness",
  #                             "moisture availability",
  #                             "competition")) +
  annotate("segment", x = 0, xend = plot_width, y = 0, yend = 0) +
    theme(axis.text.x = element_text(angle = 45, hjust = 1, colour = label_colour, face = label_face),
          plot.title = element_text(colour = title_colour, face = "italic"),
          legend.position = "none")
  return(model_plot_marg)
}

Colour scheme:

# Colour scheme ####
theme_red <- "#E64447FF"
theme_blue <- "#12435DFF"
theme_lightblue <- "#1FA3AEFF"
theme_grey <- "#EDEDEDFF"
theme_yellow <- "#EEBE5BFF"

# additional colours
theme_darkblue <- "#1D5799"
theme_darkgreen <- "#13944D"
theme_orange <- "#B56A24"
theme_purple <- "#8757B3"

Single-species models

This dataset is a new one containing predictors extracted from downscaled CHELSA climate data.

Analyses conducted on fusion table at plot \(\times\) taxon level (as we are explicitly interested in plot-level variation of predictors, esp. slope, solar radiation, terrain ruggedness, topographical wetness, and competition): 3726 observations for 38 variables

env_cov_bio <- read.csv("../data/nuuk_env_cover_plots.csv", header = T) %>% 
  # rename variable "twi_90m" to "twi"
  rename(twi = twi_90m)

Prepare data for JAGS model

a) selection of variables relevant for analysis

including predictors

  • Information on site, plot, plot group, sampling location (lat, lon, altitude), sampling year
  • downscaled CHELSA predictors, averaged over a 30-year period (*[…]_ts_30*)
  • solar radiation index (SRI, following Keating et al. 2007), slope (erosion measure), Terrain Ruggedness Index (TRI, following Riley et al. 1999), Normalised Difference Wetness Index (NDWI, Gao 1996), Tasseled Cap Wetness Index (TCWI, Crist & Ciccone 1984), SAGA Topographic Wetness Index (TWI, see Conrad et al. 2015 and the index documentation)
  • taxon (see above for levels)
  • competition pressure in the community (as summed abundance of taller-growing shrub species within a plot, averaged within plot groups)

and response variable

  • cover (as relative no. hits per plot for each species)
env_cov_bio_sub <- env_cov_bio %>% 
  select(site_alt_plotgroup_id, plot, site, site_alt_id, year, long, lat, alt,  # plot info / metadata
  ends_with("_ts_30"),   # CHELSA predictors averaged over 10-year period prior to study year
  inclin_down, twi, tri, sri, 
  #mean_summ_ndvi_yos, cv_mean_summ_ndvi_2001_to_yos, Perc_dist_coast_lines,   # environmental data
  taxon, cover, compet)   # taxon, cover response, competition pressure
head(env_cov_bio_sub)

Let’s check for correlation between the different moisture predictors and terrain ruggedness:

(cor_moist <- env_cov_bio %>% 
  select(twi, ndwi, tcws, tri)) %>% 
  correlate(diagonal = 1)

Correlation method: 'pearson'
Missing treated using: 'pairwise.complete.obs'

\(\Rightarrow\) NDWI and TCWS are highly correlated, but both are largely independent from TWI and TRI. We’ll go with TWI for now, as it is least confounded by vegetation, but will have to discuss maybe including a second index, depending on hypothesis/ecological implication.


Predictors don’t always vary between plots within plotgroups - perhaps due to several falling into the same CHELSA grid cell.

Example: plots within site 1, altitude 20, plot group 1: plot P146 is slightly off and therefore has different climate variables than the other ones

env_cov_bio %>% filter(taxon == "Betula nana" & site_alt_plotgroup_id == "1_20_1") %>% 
  ggplot(aes(x = long, y = lat)) + 
  geom_point() + 
  geom_text(aes(label = plot), hjust = 0.0001) + 
  xlim(c(-51.78675, -51.7863))

env_cov_bio %>% filter(taxon == "Betula nana" & site_alt_plotgroup_id == "1_20_1") %>% 
  select(site_alt_plotgroup_id, plot, tempjja_ts_30)

Check for correlation between predictors:

predictors_set <- env_cov_bio_sub %>% 
  select(ends_with("_ts_30"),   # CHELSA predictors averaged over 10-year period prior to study year
         inclin_down, sri, tri, twi,      # environmental data
         compet) %>% 
  names()
# create basic correlation matrix
(cor_mat <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set) %>% 
  correlate(diagonal = 1) %>% 
  # drop all values < .4 to increase readability
  mutate_if(is.numeric, ~ ifelse(abs(.) < .4, NA, .)))

Correlation method: 'pearson'
Missing treated using: 'pairwise.complete.obs'

\(\Rightarrow\) Maximum temperature is highly correlated with JJA temperature, minimum temperature with continentality, slope (inclin_down) with solar radiation, and spring precipitation variables with JJA precipitation. Let’s exclude them step by step and check the variance inflation factors (VIF) along the way. VIF values > 5 indicate collinearity issues.

# for the whole set of predictors
(vif_predictors_1 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set) %>% 
  usdm::vif()) #%>% View()
# => drop tempmax (correlated w/ tempjja)
(vif_predictors_2 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30) %>% 
  usdm::vif()) #%>% View()
# => drop tempmin (correlated w/ tempcont)
(vif_predictors_3 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30) %>% 
  usdm::vif()) #%>% View()
# => drop precipjfmam (correlated w/ precipjja & tempcont)
(vif_predictors_4 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30,
                -contains("jfm")) %>% 
  usdm::vif()) #%>% View()
# => drop inclin_down (correlated w/ SRI)
(vif_predictors_5 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30,
                -inclin_down,
                -contains("jfm")) %>% 
  usdm::vif()) #%>% View()
(vif_predictors_6 <- env_cov_bio_sub %>% 
  dplyr::select(predictors_set,
                -tempmax_ts_30,
                -tempmin_ts_30,
                -inclin_down,
                -contains("mam")) %>% 
  usdm::vif()) #%>% View()

All VIF are now < 3.1 -> OK! We can now exclude the dropped variables to obtain the final dataset:

env_cov_bio_sub <- env_cov_bio_sub %>% 
  dplyr::select(-tempmax_ts_30,
                -tempmin_ts_30,
                -inclin_down,
                -contains("mam"))

b) raw data plots

> species abundance along the gradient

(nuuk_spec_abundance_plot <- ggplot(env_cov_bio %>% 
         
         # make site a factor
         mutate(site = as.factor(site)) %>% 
         mutate(site_alt_id = factor(site_alt_id, levels = c(paste(rep(1, 3), c("20", "100", "200"), sep = "_"),
                                                             paste(rep(2, 3), c("20", "100", "200"), sep = "_"),
                                                             paste(rep(3, 5), c("20", "100", "200", "300", "400"), sep = "_"),
                                                             paste(rep(4, 6), c("20", "100", "200", "300", "400", "500"), sep = "_"),
                                                             paste(rep(5, 6), c("20", "100", "200", "300", "400", "500"), sep = "_")))) %>% 
         # group by site and isocline
         group_by(site, site_alt_id), 
       
       aes(x = site_alt_id, 
           y = cover, 
           fill = site)) + 
  
  # draw boxplots of cover
  geom_boxplot() + 
  
  # split by taxon
  facet_grid(rows = vars(taxon)) +
  
  # scale_fill_manual() +
  theme_bw() +
  xlab("site / isocline") +
  theme(strip.text.y = element_text(face = "italic"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = rel(1.2)),
        axis.title = element_text(size = rel(1.2))))


# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_species_abundance_gradient.eps"),
#           nuuk_spec_abundance_plot, base_height = 18, base_aspect_ratio = 0.8)

> predictor patterns along the gradient

# data compilation ----
predictors_set <- env_cov_bio %>% 
  select(ends_with("_ts_30"),   # CHELSA predictors averaged over 10-year period prior to study year
         inclin_down, sri, tri, twi,      # environmental data
         compet) %>% 
  names()

preds_plot_data <- env_cov_bio %>% 
         
         # convert site, isocline & plotgroup to factors
         mutate(site = as.factor(site)) %>% 
         mutate(site_alt_id = factor(site_alt_id, levels = c(paste(rep(1, 3), c("20", "100", "200"), sep = "_"),
                                                             paste(rep(2, 3), c("20", "100", "200"), sep = "_"),
                                                             paste(rep(3, 5), c("20", "100", "200", "300", "400"), sep = "_"),
                                                             paste(rep(4, 6), c("20", "100", "200", "300", "400", "500"), sep = "_"),
                                                             paste(rep(5, 6), c("20", "100", "200", "300", "400", "500"), sep = "_")))) %>% 
         mutate(plotgroup = as.factor(plotgroup)) %>% 
           
         select(site, site_alt_id, predictors_set) %>% 
         
         # pivot to long format
         pivot_longer(cols = predictors_set,
                      names_to = "predictor",
                      values_to = "value") %>% 
           
         # convert predictor col to factor
         mutate(predictor = as.factor(predictor)) %>% 
        
         # rename predictors
         mutate(predictor = fct_recode(predictor,
                                       "summer \n temperature [°C]" = "tempjja_ts_30",
                                       "yearly maximum \n temperature [°C]" = "tempmax_ts_30",
                                       "yearly minimum \n temperature [°C]" = "tempmin_ts_30",
                                       "annual temperature \n variability [°C]" = "tempcont_ts_30",
                                       "cumulative summer \n precipitation [mm]" = "precipjja_ts_30",
                                       "cumulative winter-spring \n precipitation [mm]" = "precipjfmam_ts_30",
                                       "cumulative spring \n precipitation [mm]" = "precipmam_ts_30",
                                       "slope angle [°]" = "inclin_down",
                                       "Solar Radiation \n Index" = "sri",
                                       "Terrain Ruggedness \n Index" = "tri",
                                       "Topographic Wetness \n Index" = "twi",
                                       "overgrowing \n competition" = "compet"),
                predictor = fct_relevel(predictor,
                                        "summer \n temperature [°C]",
                                        "yearly maximum \n temperature [°C]",
                                        "yearly minimum \n temperature [°C]",
                                        "annual temperature \n variability [°C]",
                                        "cumulative summer \n precipitation [mm]",
                                        "cumulative winter-spring \n precipitation [mm]",
                                        "cumulative spring \n precipitation [mm]",
                                        "slope angle [°]",
                                        "Solar Radiation \n Index",
                                        "Terrain Ruggedness \n Index",
                                        "Topographic Wetness \n Index",
                                        "overgrowing \n competition")) %>% 
           
         # group by site & isocline 
         group_by(site, site_alt_id)

# climatic predictors ----
predictors_set_clim_long <- c("summer \n temperature [°C]",
                           "yearly maximum \n temperature [°C]",
                           "yearly minimum \n temperature [°C]",
                           "annual temperature \n variability [°C]",
                           "cumulative summer \n precipitation [mm]",
                           "cumulative winter-spring \n precipitation [mm]",
                           "cumulative spring \n precipitation [mm]")

(nuuk_preds_clim_gradient_plot <- ggplot(preds_plot_data %>% 
                                           filter(predictor %in% predictors_set_clim_long),
       
       aes(x = site_alt_id, 
           y = value, 
           fill = site)) + 
  
  # draw boxplots of values
  geom_boxplot() + 
  
  # split by taxon
  facet_grid(rows = vars(predictor), scales = "free_y") +

  # scale_fill_manual() +
  theme_bw() +
  xlab("site / isocline") +
  theme(strip.text.y = element_text(face = "italic"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = rel(1.2)),
        axis.title = element_text(size = rel(1.2))))


# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_preds_clim_gradient.eps"),
#           nuuk_preds_clim_gradient_plot, base_height = 15, base_aspect_ratio = 0.8)

# environmental predictors ----
predictors_set_env_long <- c("slope angle [°]",
                           "Solar Radiation \n Index",
                           "Terrain Ruggedness \n Index",
                           "Topographic Wetness \n Index",
                           "overgrowing \n competition")

(nuuk_preds_env_gradient_plot <- ggplot(preds_plot_data %>% 
                                           filter(predictor %in% predictors_set_env_long),
       
       aes(x = site_alt_id, 
           y = value, 
           fill = site)) + 
  
  # draw boxplots of values
  geom_boxplot() + 
  
  # split by taxon
  facet_grid(rows = vars(predictor), scales = "free_y") +

  # scale_fill_manual() +
  theme_bw() +
  xlab("site / isocline") +
  theme(strip.text.y = element_text(face = "italic"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = rel(1.2)),
        axis.title = element_text(size = rel(1.2))))


# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_preds_env_gradient.eps"),
#           nuuk_preds_env_gradient_plot, base_height = 15, base_aspect_ratio = 0.8)

# final set of predictors ----
predictors_set_final_long <- c("summer \n temperature [°C]",
                               "annual temperature \n variability [°C]",
                               "cumulative summer \n precipitation [mm]",
                               "Solar Radiation \n Index",
                               "Terrain Ruggedness \n Index",
                               "Topographic Wetness \n Index",
                               "overgrowing \n competition")

(nuuk_preds_final_gradient_plot <- ggplot(preds_plot_data %>% 
                                           filter(predictor %in% predictors_set_final_long),
       
       aes(x = site_alt_id, 
           y = value, 
           fill = site)) + 
  
  # draw boxplots of values
  geom_boxplot() + 
  
  # split by taxon
  facet_grid(rows = vars(predictor), scales = "free_y") +

  # scale_fill_manual() +
  theme_bw() +
  xlab("site / isocline") +
  theme(strip.text.y = element_text(face = "italic"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = rel(1.2)),
        axis.title = element_text(size = rel(1.2))))


# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_preds_final_gradient.eps"),
#           nuuk_preds_final_gradient_plot, base_height = 15, base_aspect_ratio = 0.8)


> cover vs. predictors per species

How do the trends in cover response look for each of the predictors? Plot panels below show linear (green) and quadratic (orange) trendlines derived from linear models (different than the Bayesian approach used for analysis! but anyway useful to catch trends):

# Prepare data for panel plots for cover against predictors for each species
env_cov_bio.long <- env_cov_bio %>% 
  select(taxon,
         tempjja_ts_30,
         tempcont_ts_30,
         precipjja_ts_30,
         sri,
         tri,
         twi,
         compet,
         cover) %>% 
  # pivot to long format
  pivot_longer(cols = c(tempjja_ts_30,
                        tempcont_ts_30,
                        precipjja_ts_30,
                        sri,
                        tri,
                        twi,
                        compet),
               names_to = "predictor",
               values_to = "pred_value")

# run
pred.plot.grid(env_cov_bio.long)

c) adjustion of data structure

Data was ordered by site/altitude/plotgroup and taxon

env_cov_bio_sub <- env_cov_bio_sub[order(env_cov_bio_sub$site_alt_plotgroup_id, env_cov_bio_sub$taxon),]

As JAGS is only able to handle numeric input, all variables are assigned a numeric identifier:

env_cov_bio_sub$plotgroup.NUM <- as.numeric(factor(env_cov_bio_sub$site_alt_plotgroup_id,
                                                   levels = unique(env_cov_bio_sub$site_alt_plotgroup_id)))
env_cov_bio_sub$plot.NUM <- as.numeric(factor(env_cov_bio_sub$plot,
                                              levels = unique(env_cov_bio_sub$plot)))
env_cov_bio_sub$site_alt.NUM <- as.numeric(factor(env_cov_bio_sub$site_alt_id,
                                              levels = unique(env_cov_bio_sub$site_alt_id)))
env_cov_bio_sub$site.NUM <- as.numeric(factor(env_cov_bio_sub$site, levels = unique(env_cov_bio_sub$site)))
env_cov_bio_sub$taxon.NUM <- as.numeric(factor(env_cov_bio_sub$taxon, levels = unique(env_cov_bio_sub$taxon)))

Taxa were coded as follows:

data.frame(taxon = levels(env_cov_bio_sub$taxon),
           num = unique(env_cov_bio_sub$taxon.NUM))

Numeric predictors were scaled and centered:

num_pred <- env_cov_bio_sub %>% select(alt,
                                       ends_with("_ts_30"), 
                                       sri, 
                                       tri,
                                       starts_with("twi"), 
                                       matches("compet"))
for(i in 1:length(num_pred)){
  col <- colnames(num_pred[i])
  env_cov_bio_sub[paste0(col,"C")] <- as.numeric(scale(num_pred[i], scale = TRUE, center = TRUE))
}

To account for the range of the cover response (\(0 \leq cover \leq 1\)), the model needs a mixed structure incorporating a beta distribution (for all continuous values with \(0 < cover < 1\)) and a binomial distribution (for all discrete values of \(cover = \{0, 1\}\)). An additional variable cover_discrete was introduced to separate the dataset into discrete (= 1) and continuous (= 0) cover values:

env_cov_bio_sub$cover_discrete <- ifelse(env_cov_bio_sub$cover == 1 | env_cov_bio_sub$cover == 0, 1, 0)

Trial: Betula nana

The dataset was then ready to be split up into the species of interest. As a first trial, I focused on Betula nana:

> assembling data for model input in a list

JAGS needs data input in list format, so I provided all relevant variables as follows:

> specifying model

…and the parameters to be monitored:

> run & evaluate model

Notes at first glance:

  • quadratic fit better for temperature variables, linear fit better for precipitation variables
  • tbc

As the model converges well, we can proceed to apply it to all of the species.


All species

The dataset was then ready to be split up into the species of interest. We create separate data subsets for all/discrete/continuous response variable values for each species:

# split dataframe by taxon
env_cov_bio_sub_spec.tot <- split(env_cov_bio_sub, env_cov_bio_sub$taxon)

# assign taxon name to list elements
# >> for total datasets
for (taxon_id in 1:nlevels(env_cov_bio_sub$taxon)){
  # extract 3-letter genus name string
  assign(paste0(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id], 
                            "^\\w{3}"),
  # extract and capitalise 3-letter species name string
                str_to_title(str_remove(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id],
                                                    "\\s\\w{3}"),
                                        "\\s")),
  # add extension
                ".tot"),
  # assign to respective list element
         env_cov_bio_sub_spec.tot[[taxon_id]])
}



# >> for discrete datasets
env_cov_bio_sub_spec.dis <- list()
for (taxon_id in 1:nlevels(env_cov_bio_sub$taxon)){
  # filter for discrete response values
  env_cov_bio_sub_spec.dis[[taxon_id]] <- filter(env_cov_bio_sub_spec.tot[[taxon_id]], cover_discrete == 1)
  # extract 3-letter genus name string
  assign(paste0(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id], 
                            "^\\w{3}"),
  # extract and capitalise 3-letter species name string
                str_to_title(str_remove(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id],
                                                    "\\s\\w{3}"),
                                        "\\s")),
  # add extension
                ".dis"),
  # assign to respective list element
         env_cov_bio_sub_spec.dis[[taxon_id]])
}

# >> for continuous datasets
env_cov_bio_sub_spec.cont <- list()
for (taxon_id in 1:nlevels(env_cov_bio_sub$taxon)){
  # filter for continuous response values
  env_cov_bio_sub_spec.cont[[taxon_id]] <- filter(env_cov_bio_sub_spec.tot[[taxon_id]], cover_discrete == 0)
  # extract 3-letter genus name string
  assign(paste0(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id], 
                            "^\\w{3}"),
  # extract and capitalise 3-letter species name string
                str_to_title(str_remove(str_extract(levels(env_cov_bio_sub$taxon)[taxon_id],
                                                    "\\s\\w{3}"),
                                        "\\s")),
  # add extension
                ".cont"),
  # assign to respective list element
         env_cov_bio_sub_spec.cont[[taxon_id]])
}

> assembling data for model input in lists

JAGS needs data input in list format, so I provided all relevant variables as follows:

# Compile data into lists
# BetNan ----
shrub_gradient_jags.BetNan.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = BetNan.dis$cover,
  plotgroup.dis = BetNan.dis$plotgroup.NUM, #AB added this
  # isocline.dis = BetNan.dis$site_alt.NUM,
  # inclin_down.dis = BetNan.dis$inclin_downC,
  sri.dis = BetNan.dis$sriC,
  tri.dis = BetNan.dis$triC,
  twi.dis = BetNan.dis$twiC,
  compet.dis = BetNan.dis$competC,
  N_discrete = nrow(BetNan.dis),
  
  # ...and continuous part of the data
  cov.cont = BetNan.cont$cover,
  plotgroup.cont = BetNan.cont$plotgroup.NUM, #AB added this
  # isocline.cont = BetNan.cont$site_alt.NUM,
  # inclin_down.cont = BetNan.cont$inclin_downC,
  sri.cont = BetNan.cont$sriC,
  tri.cont = BetNan.cont$triC,
  twi.cont = BetNan.cont$twiC,
  compet.cont = BetNan.cont$competC,
  N_cont = nrow(BetNan.cont),
  
  # plot group level predictors
  tempjja.tot = BetNan.tot$tempjja_ts_30C[!duplicated(BetNan.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = BetNan.tot$tempmax_ts_30C[!duplicated(BetNan.tot$plotgroup.NUM)],
  # tempmin.tot = BetNan.tot$tempmin_ts_30C[!duplicated(BetNan.tot$plotgroup.NUM)],
  tempcont.tot = BetNan.tot$tempcont_ts_30C[!duplicated(BetNan.tot$plotgroup.NUM)],
  precipjja.tot = BetNan.tot$precipjja_ts_30C[!duplicated(BetNan.tot$plotgroup.NUM)],
  # precipjfmam.tot = BetNan.tot$precipjfmam_ts_30C[!duplicated(BetNan.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(BetNan.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = BetNan.tot$altC[!duplicated(BetNan.tot$site_alt.NUM)],
  # N_isoclines = length(unique(BetNan.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(BetNan.tot$competC), to = max(BetNan.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(BetNan.tot$sriC), to = max(BetNan.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(BetNan.tot$triC), to = max(BetNan.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(BetNan.tot$twiC), to = max(BetNan.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(BetNan.tot$tempjja_ts_30C), to = max(BetNan.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(BetNan.tot$precipjja_ts_30C), to = max(BetNan.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(BetNan.tot$tempcont_ts_30C), to = max(BetNan.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(BetNan.tot$tempjja_ts_30C,0.05),quantile(BetNan.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.BetNan.data)
List of 28
 $ cov.dis       : num [1:223] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:223] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.dis       : num [1:223] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis       : num [1:223] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.dis       : num [1:223] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.dis    : num [1:223] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_discrete    : int 223
 $ cov.cont      : num [1:191] 0.08 0.04 0.08 0.12 0.08 0.56 0.24 0.2 0.08 0.12 ...
 $ plotgroup.cont: num [1:191] 5 5 6 10 10 11 11 11 11 12 ...
 $ sri.cont      : num [1:191] 0.823 -0.248 -0.663 -0.678 -0.192 ...
 $ tri.cont      : num [1:191] 0.4613 0.3752 -0.0373 -0.2759 0.1133 ...
 $ twi.cont      : num [1:191] 1.78 1.78 1.22 -1.29 -1.29 ...
 $ compet.cont   : num [1:191] -0.477 -0.708 -0.708 -0.708 -0.708 ...
 $ N_cont        : int 191
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.671 -0.633 -0.596 -0.559 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# CasTet ----
shrub_gradient_jags.CasTet.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = CasTet.dis$cover,
  plotgroup.dis = CasTet.dis$plotgroup.NUM, #AB added this
  # isocline.dis = CasTet.dis$site_alt.NUM,
  # inclin_down.dis = CasTet.dis$inclin_downC,
  sri.dis = CasTet.dis$sriC,
  tri.dis = CasTet.dis$triC,
  twi.dis = CasTet.dis$twiC,
  compet.dis = CasTet.dis$competC,
  N_discrete = nrow(CasTet.dis),
  
  # ...and continuous part of the data
  cov.cont = CasTet.cont$cover,
  plotgroup.cont = CasTet.cont$plotgroup.NUM, #AB added this
  # isocline.cont = CasTet.cont$site_alt.NUM,
  # inclin_down.cont = CasTet.cont$inclin_downC,
  sri.cont = CasTet.cont$sriC,
  tri.cont = CasTet.cont$triC,
  twi.cont = CasTet.cont$twiC,
  compet.cont = CasTet.cont$competC,
  N_cont = nrow(CasTet.cont),
  
  # plot group level predictors
  tempjja.tot = CasTet.tot$tempjja_ts_30C[!duplicated(CasTet.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = CasTet.tot$tempmax_ts_30C[!duplicated(CasTet.tot$plotgroup.NUM)],
  # tempmin.tot = CasTet.tot$tempmin_ts_30C[!duplicated(CasTet.tot$plotgroup.NUM)],
  tempcont.tot = CasTet.tot$tempcont_ts_30C[!duplicated(CasTet.tot$plotgroup.NUM)],
  precipjja.tot = CasTet.tot$precipjja_ts_30C[!duplicated(CasTet.tot$plotgroup.NUM)],
  # precipjfmam.tot = CasTet.tot$precipjfmam_ts_30C[!duplicated(CasTet.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(CasTet.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = CasTet.tot$altC[!duplicated(CasTet.tot$site_alt.NUM)],
  # N_isoclines = length(unique(CasTet.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(CasTet.tot$competC), to = max(CasTet.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(CasTet.tot$sriC), to = max(CasTet.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(CasTet.tot$triC), to = max(CasTet.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(CasTet.tot$twiC), to = max(CasTet.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(CasTet.tot$tempjja_ts_30C), to = max(CasTet.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(CasTet.tot$precipjja_ts_30C), to = max(CasTet.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(CasTet.tot$tempcont_ts_30C), to = max(CasTet.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(CasTet.tot$tempjja_ts_30C,0.05),quantile(CasTet.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.CasTet.data)
List of 28
 $ cov.dis       : num [1:398] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:398] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.dis       : num [1:398] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis       : num [1:398] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.dis       : num [1:398] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.dis    : num [1:398] 0.796 1.722 1.028 1.375 0.796 ...
 $ N_discrete    : int 398
 $ cov.cont      : num [1:16] 0.04 0.04 0.08 0.04 0.08 0.72 0.08 0.04 0.16 0.04 ...
 $ plotgroup.cont: num [1:16] 30 30 30 38 43 49 49 49 49 49 ...
 $ sri.cont      : num [1:16] -0.314 -1.308 -0.87 0.754 -0.746 ...
 $ tri.cont      : num [1:16] 1.769 1.565 1.324 -0.807 1.567 ...
 $ twi.cont      : num [1:16] -1.36 -1.36 -1.31 1.9 -1.2 ...
 $ compet.cont   : num [1:16] 2.3011 1.1437 2.4168 -0.0138 0.5649 ...
 $ N_cont        : int 16
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.656 -0.603 -0.55 -0.498 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# EmpNig ----
shrub_gradient_jags.EmpNig.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = EmpNig.dis$cover,
  plotgroup.dis = EmpNig.dis$plotgroup.NUM, #AB added this
  # isocline.dis = EmpNig.dis$site_alt.NUM,
  # inclin_down.dis = EmpNig.dis$inclin_downC,
  sri.dis = EmpNig.dis$sriC,
  tri.dis = EmpNig.dis$triC,
  twi.dis = EmpNig.dis$twiC,
  compet.dis = EmpNig.dis$competC,
  N_discrete = nrow(EmpNig.dis),
  
  # ...and continuous part of the data
  cov.cont = EmpNig.cont$cover,
  plotgroup.cont = EmpNig.cont$plotgroup.NUM, #AB added this
  # isocline.cont = EmpNig.cont$site_alt.NUM,
  # inclin_down.cont = EmpNig.cont$inclin_downC,
  sri.cont = EmpNig.cont$sriC,
  tri.cont = EmpNig.cont$triC,
  twi.cont = EmpNig.cont$twiC,
  compet.cont = EmpNig.cont$competC,
  N_cont = nrow(EmpNig.cont),
  
  # plot group level predictors
  tempjja.tot = EmpNig.tot$tempjja_ts_30C[!duplicated(EmpNig.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = EmpNig.tot$tempmax_ts_30C[!duplicated(EmpNig.tot$plotgroup.NUM)],
  # tempmin.tot = EmpNig.tot$tempmin_ts_30C[!duplicated(EmpNig.tot$plotgroup.NUM)],
  tempcont.tot = EmpNig.tot$tempcont_ts_30C[!duplicated(EmpNig.tot$plotgroup.NUM)],
  precipjja.tot = EmpNig.tot$precipjja_ts_30C[!duplicated(EmpNig.tot$plotgroup.NUM)],
  # precipjfmam.tot = EmpNig.tot$precipjfmam_ts_30C[!duplicated(EmpNig.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(EmpNig.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = EmpNig.tot$altC[!duplicated(EmpNig.tot$site_alt.NUM)],
  # N_isoclines = length(unique(EmpNig.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(EmpNig.tot$competC), to = max(EmpNig.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(EmpNig.tot$sriC), to = max(EmpNig.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(EmpNig.tot$triC), to = max(EmpNig.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(EmpNig.tot$twiC), to = max(EmpNig.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(EmpNig.tot$tempjja_ts_30C), to = max(EmpNig.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(EmpNig.tot$precipjja_ts_30C), to = max(EmpNig.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(EmpNig.tot$tempcont_ts_30C), to = max(EmpNig.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(EmpNig.tot$tempjja_ts_30C,0.05),quantile(EmpNig.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.EmpNig.data)
List of 28
 $ cov.dis       : num [1:229] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:229] 2 2 3 5 5 6 6 6 7 7 ...
 $ sri.dis       : num [1:229] 0.9453 -1.4347 -1.4755 0.7836 -0.0244 ...
 $ tri.dis       : num [1:229] -0.9834 0.1575 0.0119 0.1007 0.1954 ...
 $ twi.dis       : num [1:229] -0.754 -0.73 -1.069 1.775 2.121 ...
 $ compet.dis    : num [1:229] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_discrete    : int 229
 $ cov.cont      : num [1:185] 0.52 0.84 0.6 0.64 0.52 0.16 0.16 0.64 0.16 0.52 ...
 $ plotgroup.cont: num [1:185] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.cont      : num [1:185] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.cont      : num [1:185] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.cont      : num [1:185] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.cont   : num [1:185] -0.708 -0.708 -0.708 -0.477 -0.708 ...
 $ N_cont        : int 185
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.665 -0.622 -0.578 -0.535 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# PhyCae ----
shrub_gradient_jags.PhyCae.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = PhyCae.dis$cover,
  plotgroup.dis = PhyCae.dis$plotgroup.NUM, #AB added this
  # isocline.dis = PhyCae.dis$site_alt.NUM,
  # inclin_down.dis = PhyCae.dis$inclin_downC,
  sri.dis = PhyCae.dis$sriC,
  tri.dis = PhyCae.dis$triC,
  twi.dis = PhyCae.dis$twiC,
  compet.dis = PhyCae.dis$competC,
  N_discrete = nrow(PhyCae.dis),
  
  # ...and continuous part of the data
  cov.cont = PhyCae.cont$cover,
  plotgroup.cont = PhyCae.cont$plotgroup.NUM, #AB added this
  # isocline.cont = PhyCae.cont$site_alt.NUM,
  # inclin_down.cont = PhyCae.cont$inclin_downC,
  sri.cont = PhyCae.cont$sriC,
  tri.cont = PhyCae.cont$triC,
  twi.cont = PhyCae.cont$twiC,
  compet.cont = PhyCae.cont$competC,
  N_cont = nrow(PhyCae.cont),
  
  # plot group level predictors
  tempjja.tot = PhyCae.tot$tempjja_ts_30C[!duplicated(PhyCae.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = PhyCae.tot$tempmax_ts_30C[!duplicated(PhyCae.tot$plotgroup.NUM)],
  # tempmin.tot = PhyCae.tot$tempmin_ts_30C[!duplicated(PhyCae.tot$plotgroup.NUM)],
  tempcont.tot = PhyCae.tot$tempcont_ts_30C[!duplicated(PhyCae.tot$plotgroup.NUM)],
  precipjja.tot = PhyCae.tot$precipjja_ts_30C[!duplicated(PhyCae.tot$plotgroup.NUM)],
  # precipjfmam.tot = PhyCae.tot$precipjfmam_ts_30C[!duplicated(PhyCae.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(PhyCae.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = PhyCae.tot$altC[!duplicated(PhyCae.tot$site_alt.NUM)],
  # N_isoclines = length(unique(PhyCae.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(PhyCae.tot$competC), to = max(PhyCae.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(PhyCae.tot$sriC), to = max(PhyCae.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(PhyCae.tot$triC), to = max(PhyCae.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(PhyCae.tot$twiC), to = max(PhyCae.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(PhyCae.tot$tempjja_ts_30C), to = max(PhyCae.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(PhyCae.tot$precipjja_ts_30C), to = max(PhyCae.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(PhyCae.tot$tempcont_ts_30C), to = max(PhyCae.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(PhyCae.tot$tempjja_ts_30C,0.05),quantile(PhyCae.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.PhyCae.data)
List of 28
 $ cov.dis       : num [1:404] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:404] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.dis       : num [1:404] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis       : num [1:404] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.dis       : num [1:404] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.dis    : num [1:404] 0.796 1.722 1.028 1.375 0.796 ...
 $ N_discrete    : int 404
 $ cov.cont      : num [1:10] 0.04 0.08 0.08 0.12 0.08 0.04 0.04 0.12 0.44 0.12
 $ plotgroup.cont: num [1:10] 9 11 14 17 24 30 36 51 51 69
 $ sri.cont      : num [1:10] -0.7393 -0.0933 -0.2978 0.4817 0.075 ...
 $ tri.cont      : num [1:10] -1.127 -0.199 0.634 -0.245 0.119 ...
 $ twi.cont      : num [1:10] -0.876 -0.637 2.047 -0.85 0.574 ...
 $ compet.cont   : num [1:10] -0.708 3.227 0.218 2.07 0.681 ...
 $ N_cont        : int 10
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.656 -0.603 -0.55 -0.498 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# RhoGro ----
shrub_gradient_jags.RhoGro.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = RhoGro.dis$cover,
  plotgroup.dis = RhoGro.dis$plotgroup.NUM, #AB added this
  # isocline.dis = RhoGro.dis$site_alt.NUM,
  # inclin_down.dis = RhoGro.dis$inclin_downC,
  sri.dis = RhoGro.dis$sriC,
  tri.dis = RhoGro.dis$triC,
  twi.dis = RhoGro.dis$twiC,
  compet.dis = RhoGro.dis$competC,
  N_discrete = nrow(RhoGro.dis),
  
  # ...and continuous part of the data
  cov.cont = RhoGro.cont$cover,
  plotgroup.cont = RhoGro.cont$plotgroup.NUM, #AB added this
  # isocline.cont = RhoGro.cont$site_alt.NUM,
  # inclin_down.cont = RhoGro.cont$inclin_downC,
  sri.cont = RhoGro.cont$sriC,
  tri.cont = RhoGro.cont$triC,
  twi.cont = RhoGro.cont$twiC,
  compet.cont = RhoGro.cont$competC,
  N_cont = nrow(RhoGro.cont),
  
  # plot group level predictors
  tempjja.tot = RhoGro.tot$tempjja_ts_30C[!duplicated(RhoGro.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = RhoGro.tot$tempmax_ts_30C[!duplicated(RhoGro.tot$plotgroup.NUM)],
  # tempmin.tot = RhoGro.tot$tempmin_ts_30C[!duplicated(RhoGro.tot$plotgroup.NUM)],
  tempcont.tot = RhoGro.tot$tempcont_ts_30C[!duplicated(RhoGro.tot$plotgroup.NUM)],
  precipjja.tot = RhoGro.tot$precipjja_ts_30C[!duplicated(RhoGro.tot$plotgroup.NUM)],
  # precipjfmam.tot = RhoGro.tot$precipjfmam_ts_30C[!duplicated(RhoGro.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(RhoGro.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = RhoGro.tot$altC[!duplicated(RhoGro.tot$site_alt.NUM)],
  # N_isoclines = length(unique(RhoGro.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(RhoGro.tot$competC), to = max(RhoGro.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(RhoGro.tot$sriC), to = max(RhoGro.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(RhoGro.tot$triC), to = max(RhoGro.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(RhoGro.tot$twiC), to = max(RhoGro.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(RhoGro.tot$tempjja_ts_30C), to = max(RhoGro.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(RhoGro.tot$precipjja_ts_30C), to = max(RhoGro.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(RhoGro.tot$tempcont_ts_30C), to = max(RhoGro.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(RhoGro.tot$tempjja_ts_30C,0.05),quantile(RhoGro.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.RhoGro.data)
List of 28
 $ cov.dis       : num [1:325] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:325] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.dis       : num [1:325] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis       : num [1:325] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.dis       : num [1:325] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.dis    : num [1:325] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_discrete    : int 325
 $ cov.cont      : num [1:89] 0.08 0.12 0.52 0.36 0.28 0.04 0.04 0.16 0.04 0.04 ...
 $ plotgroup.cont: num [1:89] 5 11 20 20 20 20 20 20 24 24 ...
 $ sri.cont      : num [1:89] 0.8231 -0.9499 -0.0661 -0.0445 -2.5788 ...
 $ tri.cont      : num [1:89] 0.4613 -0.0943 1.3399 1.4254 0.9241 ...
 $ twi.cont      : num [1:89] 1.775 -0.637 -1.027 -1.119 -1.119 ...
 $ compet.cont   : num [1:89] -0.708 -0.361 -0.708 -0.708 -0.708 ...
 $ N_cont        : int 89
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.697 -0.685 -0.673 -0.661 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# RhoTom ----
shrub_gradient_jags.RhoTom.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = RhoTom.dis$cover,
  plotgroup.dis = RhoTom.dis$plotgroup.NUM, #AB added this
  # isocline.dis = RhoTom.dis$site_alt.NUM,
  # inclin_down.dis = RhoTom.dis$inclin_downC,
  sri.dis = RhoTom.dis$sriC,
  tri.dis = RhoTom.dis$triC,
  twi.dis = RhoTom.dis$twiC,
  compet.dis = RhoTom.dis$competC,
  N_discrete = nrow(RhoTom.dis),
  
  # ...and continuous part of the data
  cov.cont = RhoTom.cont$cover,
  plotgroup.cont = RhoTom.cont$plotgroup.NUM, #AB added this
  # isocline.cont = RhoTom.cont$site_alt.NUM,
  # inclin_down.cont = RhoTom.cont$inclin_downC,
  sri.cont = RhoTom.cont$sriC,
  tri.cont = RhoTom.cont$triC,
  twi.cont = RhoTom.cont$twiC,
  compet.cont = RhoTom.cont$competC,
  N_cont = nrow(RhoTom.cont),
  
  # plot group level predictors
  tempjja.tot = RhoTom.tot$tempjja_ts_30C[!duplicated(RhoTom.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = RhoTom.tot$tempmax_ts_30C[!duplicated(RhoTom.tot$plotgroup.NUM)],
  # tempmin.tot = RhoTom.tot$tempmin_ts_30C[!duplicated(RhoTom.tot$plotgroup.NUM)],
  tempcont.tot = RhoTom.tot$tempcont_ts_30C[!duplicated(RhoTom.tot$plotgroup.NUM)],
  precipjja.tot = RhoTom.tot$precipjja_ts_30C[!duplicated(RhoTom.tot$plotgroup.NUM)],
  # precipjfmam.tot = RhoTom.tot$precipjfmam_ts_30C[!duplicated(RhoTom.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(RhoTom.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = RhoTom.tot$altC[!duplicated(RhoTom.tot$site_alt.NUM)],
  # N_isoclines = length(unique(RhoTom.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(RhoTom.tot$competC), to = max(RhoTom.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(RhoTom.tot$sriC), to = max(RhoTom.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(RhoTom.tot$triC), to = max(RhoTom.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(RhoTom.tot$twiC), to = max(RhoTom.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(RhoTom.tot$tempjja_ts_30C), to = max(RhoTom.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(RhoTom.tot$precipjja_ts_30C), to = max(RhoTom.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(RhoTom.tot$tempcont_ts_30C), to = max(RhoTom.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(RhoTom.tot$tempjja_ts_30C,0.05),quantile(RhoTom.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.RhoTom.data)
List of 28
 $ cov.dis       : num [1:401] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:401] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.dis       : num [1:401] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis       : num [1:401] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.dis       : num [1:401] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.dis    : num [1:401] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_discrete    : int 401
 $ cov.cont      : num [1:13] 0.12 0.2 0.12 0.4 0.2 0.2 0.2 0.24 0.04 0.2 ...
 $ plotgroup.cont: num [1:13] 11 11 12 30 30 36 39 39 42 43 ...
 $ sri.cont      : num [1:13] -0.95 0.723 -0.185 0.633 -1.308 ...
 $ tri.cont      : num [1:13] -0.0943 -0.2387 -0.4298 1.7289 1.5645 ...
 $ twi.cont      : num [1:13] -0.637 -0.637 0.549 -1.385 -1.362 ...
 $ compet.cont   : num [1:13] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_cont        : int 13
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# SalArc ----
shrub_gradient_jags.SalArc.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = SalArc.dis$cover,
  plotgroup.dis = SalArc.dis$plotgroup.NUM, #AB added this
  # isocline.dis = SalArc.dis$site_alt.NUM,
  # inclin_down.dis = SalArc.dis$inclin_downC,
  sri.dis = SalArc.dis$sriC,
  tri.dis = SalArc.dis$triC,
  twi.dis = SalArc.dis$twiC,
  compet.dis = SalArc.dis$competC,
  N_discrete = nrow(SalArc.dis),
  
  # ...and continuous part of the data
  cov.cont = SalArc.cont$cover,
  plotgroup.cont = SalArc.cont$plotgroup.NUM, #AB added this
  # isocline.cont = SalArc.cont$site_alt.NUM,
  # inclin_down.cont = SalArc.cont$inclin_downC,
  sri.cont = SalArc.cont$sriC,
  tri.cont = SalArc.cont$triC,
  twi.cont = SalArc.cont$twiC,
  compet.cont = SalArc.cont$competC,
  N_cont = nrow(SalArc.cont),
  
  # plot group level predictors
  tempjja.tot = SalArc.tot$tempjja_ts_30C[!duplicated(SalArc.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = SalArc.tot$tempmax_ts_30C[!duplicated(SalArc.tot$plotgroup.NUM)],
  # tempmin.tot = SalArc.tot$tempmin_ts_30C[!duplicated(SalArc.tot$plotgroup.NUM)],
  tempcont.tot = SalArc.tot$tempcont_ts_30C[!duplicated(SalArc.tot$plotgroup.NUM)],
  precipjja.tot = SalArc.tot$precipjja_ts_30C[!duplicated(SalArc.tot$plotgroup.NUM)],
  # precipjfmam.tot = SalArc.tot$precipjfmam_ts_30C[!duplicated(SalArc.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(SalArc.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = SalArc.tot$altC[!duplicated(SalArc.tot$site_alt.NUM)],
  # N_isoclines = length(unique(SalArc.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(SalArc.tot$competC), to = max(SalArc.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(SalArc.tot$sriC), to = max(SalArc.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(SalArc.tot$triC), to = max(SalArc.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(SalArc.tot$twiC), to = max(SalArc.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(SalArc.tot$tempjja_ts_30C), to = max(SalArc.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(SalArc.tot$precipjja_ts_30C), to = max(SalArc.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(SalArc.tot$tempcont_ts_30C), to = max(SalArc.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(SalArc.tot$tempjja_ts_30C,0.05),quantile(SalArc.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.SalArc.data)
List of 28
 $ cov.dis       : num [1:401] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:401] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.dis       : num [1:401] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis       : num [1:401] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.dis       : num [1:401] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.dis    : num [1:401] 0.796 1.722 1.028 1.375 0.796 ...
 $ N_discrete    : int 401
 $ cov.cont      : num [1:13] 0.04 0.04 0.08 0.04 0.04 0.04 0.04 0.2 0.08 0.04 ...
 $ plotgroup.cont: num [1:13] 4 4 5 9 16 17 18 30 43 45 ...
 $ sri.cont      : num [1:13] -1.344 -2.825 0.823 0.14 0.305 ...
 $ tri.cont      : num [1:13] 1.498 1.327 0.461 -0.478 -0.95 ...
 $ twi.cont      : num [1:13] 1.132 1.132 1.775 -0.876 -1.179 ...
 $ compet.cont   : num [1:13] 1.028 0.796 2.88 0.565 -0.13 ...
 $ N_cont        : int 13
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.656 -0.603 -0.55 -0.498 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# SalGla ----
shrub_gradient_jags.SalGla.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = SalGla.dis$cover,
  plotgroup.dis = SalGla.dis$plotgroup.NUM, #AB added this
  # isocline.dis = SalGla.dis$site_alt.NUM,
  # inclin_down.dis = SalGla.dis$inclin_downC,
  sri.dis = SalGla.dis$sriC,
  tri.dis = SalGla.dis$triC,
  twi.dis = SalGla.dis$twiC,
  compet.dis = SalGla.dis$competC,
  N_discrete = nrow(SalGla.dis),
  
  # ...and continuous part of the data
  cov.cont = SalGla.cont$cover,
  plotgroup.cont = SalGla.cont$plotgroup.NUM, #AB added this
  # isocline.cont = SalGla.cont$site_alt.NUM,
  # inclin_down.cont = SalGla.cont$inclin_downC,
  sri.cont = SalGla.cont$sriC,
  tri.cont = SalGla.cont$triC,
  twi.cont = SalGla.cont$twiC,
  compet.cont = SalGla.cont$competC,
  N_cont = nrow(SalGla.cont),
  
  # plot group level predictors
  tempjja.tot = SalGla.tot$tempjja_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = SalGla.tot$tempmax_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  # tempmin.tot = SalGla.tot$tempmin_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  tempcont.tot = SalGla.tot$tempcont_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  precipjja.tot = SalGla.tot$precipjja_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  # precipjfmam.tot = SalGla.tot$precipjfmam_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(SalGla.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = SalGla.tot$altC[!duplicated(SalGla.tot$site_alt.NUM)],
  # N_isoclines = length(unique(SalGla.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(SalGla.tot$competC), to = max(SalGla.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(SalGla.tot$sriC), to = max(SalGla.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(SalGla.tot$triC), to = max(SalGla.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(SalGla.tot$twiC), to = max(SalGla.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(SalGla.tot$tempjja_ts_30C), to = max(SalGla.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(SalGla.tot$precipjja_ts_30C), to = max(SalGla.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(SalGla.tot$tempcont_ts_30C), to = max(SalGla.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(SalGla.tot$tempjja_ts_30C,0.05),quantile(SalGla.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.SalGla.data)
List of 28
 $ cov.dis       : num [1:289] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:289] 1 1 1 1 1 1 2 2 2 2 ...
 $ sri.dis       : num [1:289] 0.51 0.829 1.034 0.37 0.573 ...
 $ tri.dis       : num [1:289] -0.274 -0.318 -0.301 -0.274 -0.176 ...
 $ twi.dis       : num [1:289] 0.144 0.144 0.144 -0.384 -0.384 ...
 $ compet.dis    : num [1:289] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_discrete    : int 289
 $ cov.cont      : num [1:125] 0.32 0.12 0.2 0.08 0.44 0.08 0.04 0.12 0.04 0.04 ...
 $ plotgroup.cont: num [1:125] 2 2 4 4 6 8 11 11 12 14 ...
 $ sri.cont      : num [1:125] -1.562 -0.758 0.646 -2.68 -0.409 ...
 $ tri.cont      : num [1:125] -0.0114 0.1046 -0.9626 1.4106 0.1025 ...
 $ twi.cont      : num [1:125] -0.73 -0.73 1.13 1.13 1.96 ...
 $ compet.cont   : num [1:125] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_cont        : int 125
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.686 -0.664 -0.642 -0.619 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2
# VacUli ----
shrub_gradient_jags.VacUli.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = VacUli.dis$cover,
  plotgroup.dis = VacUli.dis$plotgroup.NUM, #AB added this
  # isocline.dis = VacUli.dis$site_alt.NUM,
  # inclin_down.dis = VacUli.dis$inclin_downC,
  sri.dis = VacUli.dis$sriC,
  tri.dis = VacUli.dis$triC,
  twi.dis = VacUli.dis$twiC,
  compet.dis = VacUli.dis$competC,
  N_discrete = nrow(VacUli.dis),
  
  # ...and continuous part of the data
  cov.cont = VacUli.cont$cover,
  plotgroup.cont = VacUli.cont$plotgroup.NUM, #AB added this
  # isocline.cont = VacUli.cont$site_alt.NUM,
  # inclin_down.cont = VacUli.cont$inclin_downC,
  sri.cont = VacUli.cont$sriC,
  tri.cont = VacUli.cont$triC,
  twi.cont = VacUli.cont$twiC,
  compet.cont = VacUli.cont$competC,
  N_cont = nrow(VacUli.cont),
  
  # plot group level predictors
  tempjja.tot = VacUli.tot$tempjja_ts_30C[!duplicated(VacUli.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = VacUli.tot$tempmax_ts_30C[!duplicated(VacUli.tot$plotgroup.NUM)],
  # tempmin.tot = VacUli.tot$tempmin_ts_30C[!duplicated(VacUli.tot$plotgroup.NUM)],
  tempcont.tot = VacUli.tot$tempcont_ts_30C[!duplicated(VacUli.tot$plotgroup.NUM)],
  precipjja.tot = VacUli.tot$precipjja_ts_30C[!duplicated(VacUli.tot$plotgroup.NUM)],
  # precipjfmam.tot = VacUli.tot$precipjfmam_ts_30C[!duplicated(VacUli.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(VacUli.tot$site_alt_plotgroup_id)),
  
  # # site/alt level predictors
  # alt.tot = VacUli.tot$altC[!duplicated(VacUli.tot$site_alt.NUM)],
  # N_isoclines = length(unique(VacUli.tot$site_alt_id))
  
  # subset of values for prediction, for each predictor...
  xhat_compet = seq(from = min(VacUli.tot$competC), to = max(VacUli.tot$competC), length.out = 100),
  xhat_sri = seq(from = min(VacUli.tot$sriC), to = max(VacUli.tot$sriC), length.out = 100),
  xhat_tri = seq(from = min(VacUli.tot$triC), to = max(VacUli.tot$triC), length.out = 100),
  xhat_twi = seq(from = min(VacUli.tot$twiC), to = max(VacUli.tot$twiC), length.out = 100),
  xhat_tempjja = seq(from = min(VacUli.tot$tempjja_ts_30C), to = max(VacUli.tot$tempjja_ts_30C), length.out = 100),
  xhat_precipjja = seq(from = min(VacUli.tot$precipjja_ts_30C), to = max(VacUli.tot$precipjja_ts_30C), length.out = 100),
  xhat_tempcont = seq(from = min(VacUli.tot$tempcont_ts_30C), to = max(VacUli.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100,
  
  # ... and for predicting at high/low temperature levels
  xhat_tempjja2 = as.numeric(c(quantile(VacUli.tot$tempjja_ts_30C,0.05),quantile(VacUli.tot$tempjja_ts_30C,0.95))), 
  Nxhat2 = 2
)
str(shrub_gradient_jags.VacUli.data)
List of 28
 $ cov.dis       : num [1:309] 0 0 0 0 0 0 0 0 0 0 ...
 $ plotgroup.dis : num [1:309] 1 1 1 1 2 2 2 2 2 2 ...
 $ sri.dis       : num [1:309] 0.51 0.829 1.034 0.573 0.945 ...
 $ tri.dis       : num [1:309] -0.274 -0.318 -0.301 -0.176 -0.983 ...
 $ twi.dis       : num [1:309] 0.144 0.144 0.144 -0.384 -0.754 ...
 $ compet.dis    : num [1:309] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_discrete    : int 309
 $ cov.cont      : num [1:105] 0.08 0.04 0.24 0.28 0.08 0.32 0.36 0.28 0.08 0.16 ...
 $ plotgroup.cont: num [1:105] 1 1 3 3 4 4 5 10 10 11 ...
 $ sri.cont      : num [1:105] 0.37 0.688 -0.207 -1.955 -0.556 ...
 $ tri.cont      : num [1:105] -0.274 0.187 0.138 0.355 1.316 ...
 $ twi.cont      : num [1:105] -0.384 -0.384 -1.069 -1.069 1.132 ...
 $ compet.cont   : num [1:105] -0.708 -0.708 -0.708 -0.708 -0.708 ...
 $ N_cont        : int 105
 $ tempjja.tot   : num [1:69] -0.321 -0.283 -0.226 -0.395 -0.42 ...
 $ tempcont.tot  : num [1:69] -2.45 -2.52 -2.49 -2.41 -2.39 ...
 $ precipjja.tot : num [1:69] 0.713 0.866 1.044 0.626 0.593 ...
 $ N_plotgroups  : int 69
 $ xhat_compet   : num [1:100] -0.708 -0.667 -0.626 -0.585 -0.545 ...
 $ xhat_sri      : num [1:100] -3.1 -3.06 -3.02 -2.98 -2.94 ...
 $ xhat_tri      : num [1:100] -1.71 -1.65 -1.59 -1.53 -1.47 ...
 $ xhat_twi      : num [1:100] -1.7 -1.66 -1.62 -1.57 -1.53 ...
 $ xhat_tempjja  : num [1:100] -2.57 -2.52 -2.48 -2.44 -2.4 ...
 $ xhat_precipjja: num [1:100] -1.66 -1.62 -1.58 -1.55 -1.51 ...
 $ xhat_tempcont : num [1:100] -2.52 -2.49 -2.45 -2.42 -2.38 ...
 $ Nxhat         : num 100
 $ xhat_tempjja2 : num [1:2] -2.01 1.31
 $ Nxhat2        : num 2

> specifying model

write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.twi ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      b.precipjja.x2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.twi * twi.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.twi * twi.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] + 
                    b.precipjja.x2 * (precipjja.tot[k]^2) 
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_sri[m] <- intercept + b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + b.tri * xhat_tri[m]
        phat_twi[m] <- intercept + b.twi * xhat_twi[m]
        phat_tempjja[m] <- intercept + b.tempjja.x * xhat_tempjja[m] + b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + b.tempcont.x * xhat_tempcont[m] + b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + b.precipjja.x * xhat_precipjja[m] + b.precipjja.x2 * (xhat_precipjja[m]^2)
      }

    
      }
  ", file.path("..", "models", "shrub_gradient.spec.jags"))

Specify the parameters to be monitored:

params <- c("intercept",
            "b.tempjja.x", "b.tempjja.x2",
            "b.tempcont.x", "b.tempcont.x2",
            "b.precipjja.x", "b.precipjja.x2",
            "b.compet", 
            "b.sri",
            "b.tri",
            "b.twi",
            "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
            "sigma.plotgroup",
            "phi",
            "phat_compet", "phat_sri", "phat_tri", "phat_twi", "phat_tempjja", "phat_tempcont", "phat_precipjja")

> run & evaluate model


Betula nana

# run model
model_out.shrub_gradient.BetNan <- jags(shrub_gradient_jags.BetNan.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text") 
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 8536

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.BetNan) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.BetNan <- model_out.shrub_gradient.BetNan$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.BetNan),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.BetNan <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.BetNan$BUGSoutput$sims.list)-4)){
  ci_90.BetNan[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.BetNan$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.BetNan[param, 3] <- names(data.frame(model_out.shrub_gradient.BetNan$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.BetNan <- coeff.shrub_gradient.BetNan %>% 
  left_join(ci_90.BetNan, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

(effect_size_plot.BetNan <- model_plot_marg_function(coeff.shrub_gradient.BetNan, title_string = "Betula nana", plot_width = 11))

  • unimodal response to temperature variability (sig)
  • slightly negative response to competition & precipitation (linear) (n.s.)


As the quadratic terms for summer temperature and precipitation were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.twi ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      # b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.twi * twi.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.twi * twi.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2)
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_sri[m] <- intercept + 
                        b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + 
                        b.tri * xhat_tri[m]
        phat_twi[m] <- intercept + 
                        b.twi * xhat_twi[m]
        phat_tempjja[m] <- intercept + 
                            b.tempjja.x * xhat_tempjja[m] # + 
                            # b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + 
                            b.tempcont.x * xhat_tempcont[m] + 
                            b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + 
                              b.precipjja.x * xhat_precipjja[m] # + 
                              # b.precipjja.x2 * (xhat_precipjja[m]^2)
        
        for (p in 1:Nxhat2){
          phat_tempcontXtemp[m,p] <- intercept +
                                      b.tempcont.x * xhat_tempcont[m] +
                                      b.tempcont.x2 * (xhat_tempcont[m]^2) +
                                      b.tempjja.x * xhat_tempjja2[p] # +
                                      # b.tempjja.x2 * (xhat_tempjja2[p]^2)
        }
      }
    
      }
  ", file.path("..", "models", "shrub_gradient.BetNan2.jags"))

# specify new set of parameters to be monitored
params_BetNan2 <- c("intercept",
                    "b.tempjja.x", # "b.tempjja.x2",
                    "b.tempcont.x", "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.sri",
                    "b.tri",
                    "b.twi",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_sri", "phat_tri", "phat_twi", "phat_tempjja", "phat_tempcont", "phat_precipjja", "phat_tempcontXtemp")

model_out.shrub_gradient.BetNan2 <- jags(shrub_gradient_jags.BetNan.data,   # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_BetNan2,                     # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.BetNan2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 80
   Total graph size: 8065

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.BetNan2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.BetNan2 <- model_out.shrub_gradient.BetNan2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.BetNan2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.BetNan2$BUGSoutput$sims.list)-4)){
  ci_90.BetNan2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.BetNan2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.BetNan2[param, 3] <- names(data.frame(model_out.shrub_gradient.BetNan2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.BetNan2 <- coeff.shrub_gradient.BetNan2 %>% 
  left_join(ci_90.BetNan2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.BetNan2 <- model_plot_marg_function(coeff.shrub_gradient.BetNan2, title_string = "Betula nana", plot_width = 8.5))

  • unimodal response to temperature variability (m.s.)
  • slightly negative response to competition & precipitation (linear) (n.s.)


Cassiope tetragona

model_out.shrub_gradient.CasTet <- jags(shrub_gradient_jags.CasTet.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 8016

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.CasTet) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.CasTet <- model_out.shrub_gradient.CasTet$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.CasTet),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.CasTet <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.CasTet$BUGSoutput$sims.list)-4)){
  ci_90.CasTet[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.CasTet$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.CasTet[param, 3] <- names(data.frame(model_out.shrub_gradient.CasTet$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.CasTet <- coeff.shrub_gradient.CasTet %>% 
  left_join(ci_90.CasTet, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# (effect_size_plot.CasTet <- model_plot_function(coeff.shrub_gradient.CasTet))
  • not converging: really large R-hat values (only 16 non-zero values)

Empetrum nigrum

model_out.shrub_gradient.EmpNig <- jags(shrub_gradient_jags.EmpNig.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 8528

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.EmpNig) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.EmpNig <- model_out.shrub_gradient.EmpNig$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.EmpNig),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.EmpNig <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.EmpNig$BUGSoutput$sims.list)-4)){
  ci_90.EmpNig[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.EmpNig$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.EmpNig[param, 3] <- names(data.frame(model_out.shrub_gradient.EmpNig$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.EmpNig <- coeff.shrub_gradient.EmpNig %>% 
  left_join(ci_90.EmpNig, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.EmpNig <- model_plot_sig_function(coeff.shrub_gradient.EmpNig, title_string = "Empetrum nigrum", plot_width = 11))

  • positive response to precipitation (linear, sig.)
  • unimodal response to temperature (m.s.)
  • slightly positive response to competition, SRI and TWI (n.s.)

As the quadratic terms for temperature variability and precipitation were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.twi ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + #AB added this, ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.twi * twi.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + #AB added this, ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.twi * twi.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2)
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_sri[m] <- intercept + 
                        b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + 
                        b.tri * xhat_tri[m]
        phat_twi[m] <- intercept + 
                        b.twi * xhat_twi[m]
        phat_tempjja[m] <- intercept + 
                            b.tempjja.x * xhat_tempjja[m] + 
                            b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + 
                            b.tempcont.x * xhat_tempcont[m] # + 
                            # b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + 
                              b.precipjja.x * xhat_precipjja[m] # + 
                              # b.precipjja.x2 * (xhat_precipjja[m]^2)
        
        for (p in 1:Nxhat2){
          phat_tempcontXtemp[m,p] <- intercept +
                                      b.tempcont.x * xhat_tempcont[m] +
                                      # b.tempcont.x2 * (xhat_tempcont[m]^2) +
                                      b.tempjja.x * xhat_tempjja2[p] +
                                      b.tempjja.x2 * (xhat_tempjja2[p]^2)
        }
      }

    
      }
  ", file.path("..", "models", "shrub_gradient.EmpNig2.jags"))

# specify new set of parameters to be monitored
params_EmpNig2 <- c("intercept",
                    "b.tempjja.x", "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.sri",
                    "b.tri",
                    "b.twi",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_sri", "phat_tri", "phat_twi", "phat_tempjja", "phat_tempcont", "phat_precipjja", "phat_tempcontXtemp")

model_out.shrub_gradient.EmpNig2 <- jags(shrub_gradient_jags.EmpNig.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_EmpNig2,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.EmpNig2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 80
   Total graph size: 8063

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.EmpNig2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.EmpNig2 <- model_out.shrub_gradient.EmpNig2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.EmpNig2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.EmpNig$BUGSoutput$sims.list)-4)){
  ci_90.EmpNig2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.EmpNig2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.EmpNig2[param, 3] <- names(data.frame(model_out.shrub_gradient.EmpNig2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.EmpNig2 <- coeff.shrub_gradient.EmpNig2 %>% 
  left_join(ci_90.EmpNig2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.EmpNig2 <- model_plot_marg_function(coeff.shrub_gradient.EmpNig2, title_string = "Empetrum nigrum", plot_width = 8.5))

  • unimodal response to temperature, positive response to precipitation (linear) (sig.), negative response to temp. variability (m.s.)
  • positive response to competition, TWI (n.s.)


Phyllodoce caerulea

model_out.shrub_gradient.PhyCae <- jags(shrub_gradient_jags.PhyCae.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 7999

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.PhyCae) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.PhyCae <- model_out.shrub_gradient.PhyCae$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.PhyCae),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.PhyCae <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.PhyCae$BUGSoutput$sims.list)-4)){
  ci_90.PhyCae[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.PhyCae$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.PhyCae[param, 3] <- names(data.frame(model_out.shrub_gradient.PhyCae$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.PhyCae <- coeff.shrub_gradient.PhyCae %>% 
  left_join(ci_90.PhyCae, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print
NA
  • not converged (only 10 non-zero values)

Rhododendron groenlandicum

model_out.shrub_gradient.RhoGro <- jags(shrub_gradient_jags.RhoGro.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 8210

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.RhoGro) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.RhoGro <- model_out.shrub_gradient.RhoGro$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.RhoGro),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.RhoGro <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.RhoGro$BUGSoutput$sims.list)-4)){
  ci_90.RhoGro[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.RhoGro$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.RhoGro[param, 3] <- names(data.frame(model_out.shrub_gradient.RhoGro$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.RhoGro <- coeff.shrub_gradient.RhoGro %>% 
  left_join(ci_90.RhoGro, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.RhoGro <- model_plot_sig_function(coeff.shrub_gradient.RhoGro, title_string = "Rhododendron groenlandicum", plot_width = 11))

  • unimodal response to temperature & linear to precipitation (sig.)
  • slightly positive response to SRI, temp. variation (n.s.)
  • slightly negative responst to TWI (n.s.)
  • large variation in competiton response as there was only one (however rare) taller-growing species in the system (R. tomentosum)


As the quadratic terms for temperature variability and precipitation were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.twi ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.twi * twi.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.twi * twi.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2)
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_sri[m] <- intercept + 
                        b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + 
                        b.tri * xhat_tri[m]
        phat_twi[m] <- intercept + 
                        b.twi * xhat_twi[m]
        phat_tempjja[m] <- intercept + 
                            b.tempjja.x * xhat_tempjja[m] + 
                            b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + 
                            b.tempcont.x * xhat_tempcont[m] # + 
                            # b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + 
                              b.precipjja.x * xhat_precipjja[m] # + 
                              # b.precipjja.x2 * (xhat_precipjja[m]^2)
        
        for (p in 1:Nxhat2){
          phat_tempcontXtemp[m,p] <- intercept +
                                      b.tempcont.x * xhat_tempcont[m] +
                                      # b.tempcont.x2 * (xhat_tempcont[m]^2) +
                                      b.tempjja.x * xhat_tempjja2[p] +
                                      b.tempjja.x2 * (xhat_tempjja2[p]^2)
        }
      }

    
      }
  ", file.path("..", "models", "shrub_gradient.RhoGro2.jags"))

# specify new set of parameters to be monitored
params_RhoGro2 <- c("intercept",
                    "b.tempjja.x", "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.sri",
                    "b.tri",
                    "b.twi",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_sri", "phat_tri", "phat_twi", "phat_tempjja", "phat_tempcont", "phat_precipjja", "phat_tempcontXtemp")

model_out.shrub_gradient.RhoGro2 <- jags(shrub_gradient_jags.RhoGro.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_RhoGro2,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.RhoGro2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 80
   Total graph size: 7745

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.RhoGro2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.RhoGro2 <- model_out.shrub_gradient.RhoGro2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.RhoGro),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.RhoGro2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.RhoGro$BUGSoutput$sims.list)-4)){
  ci_90.RhoGro2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.RhoGro2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.RhoGro2[param, 3] <- names(data.frame(model_out.shrub_gradient.RhoGro2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.RhoGro2 <- coeff.shrub_gradient.RhoGro2 %>% 
  left_join(ci_90.RhoGro2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.RhoGro2 <- model_plot_sig_function(coeff.shrub_gradient.RhoGro2, title_string = "Rhododendron groenlandicum", plot_width = 8.5))

  • unimodal response to temperature and negative response to precipitation (linear), positive response to temperature variability (sig.)
  • positive response to SRI (n.s.)
  • large variation in competiton response as there was only one (however rare) taller-growing species in the system (R. tomentosum)


Rhododendron tomentosum

model_out.shrub_gradient.RhoTom <- jags(shrub_gradient_jags.RhoTom.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 7780

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.RhoTom) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.RhoTom <- model_out.shrub_gradient.RhoTom$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.RhoTom),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.RhoTom <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.RhoTom$BUGSoutput$sims.list)-4)){
  ci_90.RhoTom[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.RhoTom$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.RhoTom[param, 3] <- names(data.frame(model_out.shrub_gradient.RhoTom$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.RhoTom <- coeff.shrub_gradient.RhoTom %>% 
  left_join(ci_90.RhoTom, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print
NA
  • not converging: relatively large R-hat values, large variation in parameter estimates (only 13 non-zero values)

Salix arctophila

model_out.shrub_gradient.SalArc <- jags(shrub_gradient_jags.SalArc.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 8008

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.SalArc) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.SalArc <- model_out.shrub_gradient.SalArc$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.SalArc),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.SalArc <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.SalArc$BUGSoutput$sims.list)-4)){
  ci_90.SalArc[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalArc$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.SalArc[param, 3] <- names(data.frame(model_out.shrub_gradient.SalArc$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.SalArc <- coeff.shrub_gradient.SalArc %>% 
  left_join(ci_90.SalArc, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print
NA
  • not converging well: relatively large R-hat values, quite some variation in parameter estimates (only 13 non-zero values)

Salix glauca

model_out.shrub_gradient.SalGla <- jags(shrub_gradient_jags.SalGla.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 8331

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.SalGla) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.SalGla <- model_out.shrub_gradient.SalGla$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.SalGla),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.SalGla <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list)-4)){
  ci_90.SalGla[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.SalGla[param, 3] <- names(data.frame(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.SalGla <- coeff.shrub_gradient.SalGla %>% 
  left_join(ci_90.SalGla, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.SalGla <- model_plot_sig_function(coeff.shrub_gradient.SalGla, title_string = "Salix glauca", plot_width = 11))

  • positive response to competition (sig.)
  • slightly negative response to temperature & SRI (n.s.)


As the quadratic terms for summer temperature, temperature variability and summer precipitation were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.twi ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.twi * twi.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.twi * twi.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    # b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2)
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_sri[m] <- intercept + 
                        b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + 
                        b.tri * xhat_tri[m]
        phat_twi[m] <- intercept + 
                        b.twi * xhat_twi[m]
        phat_tempjja[m] <- intercept + 
                            b.tempjja.x * xhat_tempjja[m] # + 
                            # b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + 
                            b.tempcont.x * xhat_tempcont[m] # + 
                            # b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + 
                              b.precipjja.x * xhat_precipjja[m] # + 
                              # b.precipjja.x2 * (xhat_precipjja[m]^2)
        
        for (p in 1:Nxhat2){
          phat_tempcontXtemp[m,p] <- intercept +
                                      b.tempcont.x * xhat_tempcont[m] +
                                      # b.tempcont.x2 * (xhat_tempcont[m]^2) +
                                      b.tempjja.x * xhat_tempjja2[p] # +
                                      # b.tempjja.x2 * (xhat_tempjja2[p]^2)
        }
      }

    
      }
  ", file.path("..", "models", "shrub_gradient.SalGla2.jags"))

# specify new set of parameters to be monitored
params_SalGla2 <- c("intercept",
                    "b.tempjja.x", # "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.sri",
                    "b.tri",
                    "b.twi",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_sri", "phat_tri", "phat_twi", "phat_tempjja", "phat_tempcont", "phat_precipjja", "phat_tempcontXtemp")

model_out.shrub_gradient.SalGla2 <- jags(shrub_gradient_jags.SalGla.data,   # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_SalGla2,                     # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.SalGla2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 80
   Total graph size: 7523

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.SalGla2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.SalGla2 <- model_out.shrub_gradient.SalGla2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.SalGla2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.SalGla$BUGSoutput$sims.list)-4)){
  ci_90.SalGla2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.SalGla2[param, 3] <- names(data.frame(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.SalGla2 <- coeff.shrub_gradient.SalGla2 %>% 
  left_join(ci_90.SalGla2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.SalGla2 <- model_plot_marg_function(coeff.shrub_gradient.SalGla2, title_string = "Salix glauca", plot_width = 8))

  • positive response to temperature variability (linear) and competition (sig.)
  • positive response to TRI, negative response to SRI (n.s.)


Vaccinium uliginosum

model_out.shrub_gradient.VacUli <- jags(shrub_gradient_jags.VacUli.data,    # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params,                             # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.spec.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Unused variable "xhat_tempjja2" in dataUnused variable "Nxhat2" in data
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 82
   Total graph size: 8284

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.VacUli) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.VacUli <- model_out.shrub_gradient.VacUli$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.VacUli),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.VacUli <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.VacUli$BUGSoutput$sims.list)-4)){
  ci_90.VacUli[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.VacUli$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.VacUli[param, 3] <- names(data.frame(model_out.shrub_gradient.VacUli$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.VacUli <- coeff.shrub_gradient.VacUli %>% 
  left_join(ci_90.VacUli, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.VacUli <- model_plot_marg_function(coeff.shrub_gradient.VacUli, title_string = "Vaccinium uliginosum", plot_width = 11))

  • unimodal response to temperature (sig.), TWI, competition (m.s.)
  • positive response to SRI (n.s.)


As the quadratic terms for temperature variability and precipitation were not significant, they were removed from the model before re-running:

# new model object with terms removed
write("
  
  model{
    
    # priors
      
      intercept ~ dnorm(0, 0.0001)
      
      b.compet ~ dnorm(0, 0.0001)
      b.sri ~ dnorm(0, 0.0001)
      b.tri ~ dnorm(0, 0.0001)
      b.twi ~ dnorm(0, 0.0001)

      sigma.plotgroup ~ dunif(0,100)
      tau.plotgroup <- 1/(sigma.plotgroup * sigma.plotgroup)
      
      b.tempjja.x ~ dnorm(0, 0.001)
      b.tempjja.x2 ~ dnorm(0, 0.001)
      b.tempcont.x ~ dnorm(0, 0.001)
      # b.tempcont.x2 ~ dnorm(0, 0.001)
      b.precipjja.x ~ dnorm(0, 0.001)
      # b.precipjja.x2 ~ dnorm(0, 0.001)
      
      phi ~ dgamma(0.1, 0.1)
      
      
    # LIKELIHOOD for discrete part

      for (i in 1:N_discrete){ 
        cov.dis[i] ~ dbern(mu[i])
        logit(mu[i]) <- b_plotgroup[plotgroup.dis[i]] + # ~= random effect of plot group
                        b.compet * compet.dis[i] + 
                        b.twi * twi.dis[i] + 
                        b.sri * sri.dis[i] +
                        b.tri * tri.dis[i]
      }
      
      
    # LIKELIHOOD for continuous part

      for (j in 1:N_cont){
        cov.cont[j] ~ dbeta(p[j], q[j])
        p[j] <- mu2[j] * phi
        q[j] <- (1 - mu2[j]) * phi
        logit(mu2[j]) <- b_plotgroup[plotgroup.cont[j]] + # ~= random effect of plot group
                        b.compet * compet.cont[j] +
                        b.twi * twi.cont[j] + 
                        b.sri * sri.cont[j] +
                        b.tri * tri.cont[j]
      }

      for (k in 1:N_plotgroups){ # length of total plotgroups
        b_plotgroup[k] ~ dnorm(mu.plotgroup[k],tau.plotgroup)
        mu.plotgroup[k] <- intercept + 
                    
                    # plot group level predictors, linear and quadratic term
                    b.tempjja.x * tempjja.tot[k] + 
                    b.tempjja.x2 * (tempjja.tot[k]^2) + 
                    b.tempcont.x * tempcont.tot[k] + 
                    # b.tempcont.x2 * (tempcont.tot[k]^2) +
                    b.precipjja.x * precipjja.tot[k] # + 
                    # b.precipjja.x2 * (precipjja.tot[k]^2)
      }
      
      
      # add predicted values (derived parameters)
      for (m in 1:Nxhat){
        phat_compet[m] <- intercept + b.compet * xhat_compet[m]
        phat_sri[m] <- intercept + 
                        b.sri * xhat_sri[m]
        phat_tri[m] <- intercept + 
                        b.tri * xhat_tri[m]
        phat_twi[m] <- intercept + 
                        b.twi * xhat_twi[m]
        phat_tempjja[m] <- intercept + 
                            b.tempjja.x * xhat_tempjja[m] + 
                            b.tempjja.x2 * (xhat_tempjja[m]^2)
        phat_tempcont[m] <- intercept + 
                            b.tempcont.x * xhat_tempcont[m] # + 
                            # b.tempcont.x2 * (xhat_tempcont[m]^2)
        phat_precipjja[m] <- intercept + 
                              b.precipjja.x * xhat_precipjja[m] # + 
                              # b.precipjja.x2 * (xhat_precipjja[m]^2)
        
        for (p in 1:Nxhat2){
          phat_tempcontXtemp[m,p] <- intercept +
                                      b.tempcont.x * xhat_tempcont[m] +
                                      # b.tempcont.x2 * (xhat_tempcont[m]^2) +
                                      b.tempjja.x * xhat_tempjja2[p] +
                                      b.tempjja.x2 * (xhat_tempjja2[p]^2)
        }
      }

    
      }
  ", file.path("..", "models", "shrub_gradient.VacUli2.jags"))

# specify new set of parameters to be monitored
params_VacUli2 <- c("intercept",
                    "b.tempjja.x", "b.tempjja.x2",
                    "b.tempcont.x", # "b.tempcont.x2",
                    "b.precipjja.x", # "b.precipjja.x2",
                    "b.compet", 
                    "b.sri",
                    "b.tri",
                    "b.twi",
                    "b_plotgroup[1]","b_plotgroup[2]","b_plotgroup[3]","b_plotgroup[63]",
                    "sigma.plotgroup",
                    "phi",
                    "phat_compet", "phat_sri", "phat_tri", "phat_twi", "phat_tempjja", "phat_tempcont", "phat_precipjja", "phat_tempcontXtemp")

model_out.shrub_gradient.VacUli2 <- jags(shrub_gradient_jags.VacUli.data,   # input data
                                        inits = NULL,                       # JAGS to create initial values
                                        params_VacUli2,                     # parameters to be saved
                                        model.file = file.path("..", "models", "shrub_gradient.VacUli2.jags"), 
                                        n.chains = 3,                       # no. Markov chains
                                        n.iter = 100000, n.burnin = 70000,  # no. iterations & burn-in fraction per chain
                                        n.thin = 2,                         # thinning rate
                                        DIC = FALSE,                        # do not compute deviance, pD, and DIC
                                        working.directory = NULL, 
                                        progress.bar = "text")
Compiling model graph
   Resolving undeclared variables
   Allocating nodes
Graph information:
   Observed stochastic nodes: 414
   Unobserved stochastic nodes: 80
   Total graph size: 7819

Initializing model


  |                                                        
  |                                                  |   0%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%

  |                                                        
  |                                                  |   0%
  |                                                        
  |***                                               |   7%
  |                                                        
  |*******                                           |  13%
  |                                                        
  |**********                                        |  20%
  |                                                        
  |*************                                     |  27%
  |                                                        
  |*****************                                 |  33%
  |                                                        
  |********************                              |  40%
  |                                                        
  |***********************                           |  47%
  |                                                        
  |***************************                       |  53%
  |                                                        
  |******************************                    |  60%
  |                                                        
  |*********************************                 |  67%
  |                                                        
  |*************************************             |  73%
  |                                                        
  |****************************************          |  80%
  |                                                        
  |*******************************************       |  87%
  |                                                        
  |***********************************************   |  93%
  |                                                        
  |**************************************************| 100%
# plot(model_out.shrub_gradient.VacUli2) #check convergence, etc.

Extract coefficients and plot effect sizes:

# extract coefficients 
coeff.shrub_gradient.VacUli2 <- model_out.shrub_gradient.VacUli2$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")

# add 90% CIs
ci_90.VacUli2 <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.VacUli$BUGSoutput$sims.list)-4)){
  ci_90.VacUli2[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.VacUli2$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.VacUli2[param, 3] <- names(data.frame(model_out.shrub_gradient.VacUli2$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.VacUli2 <- coeff.shrub_gradient.VacUli2 %>% 
  left_join(ci_90.VacUli2, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.VacUli2 <- model_plot_marg_function(coeff.shrub_gradient.VacUli2, title_string = "Vaccinium uliginosum", plot_width = 8.5))

  • unimodal response to temperature (sig.), TWI (m.s.)
  • negative response to competition, positive response to SRI (n.s.)


> combine all plots

# 3x2 grid (vertical layout)
(nuuk_effectsize_plot_grid_ver <- plot_grid(effect_size_plot.BetNan, 
                                            effect_size_plot.EmpNig, 
                                            effect_size_plot.RhoGro, 
                                            effect_size_plot.SalGla, 
                                            effect_size_plot.VacUli,
                                            labels = c("a)", "b)", "c)", "d)", "e)"),
                                            label_size = 20,
                                            label_fontface = "plain",
                                            hjust = -2,
                                            ncol = 2))

# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_betabinom_effect_size_panels_vert.eps"),
#           nuuk_effectsize_plot_grid_ver, base_height = 15, base_aspect_ratio = 0.8)

# 3x2 grid reduced predictor terms
(nuuk_reduced_effectsize_plot_grid_ver <- plot_grid(effect_size_plot.BetNan2, 
                                            effect_size_plot.EmpNig2, 
                                            effect_size_plot.RhoGro2, 
                                            effect_size_plot.SalGla2, 
                                            effect_size_plot.VacUli2,
                                            labels = c("a)", "b)", "c)", "d)", "e)"),
                                            label_size = 20,
                                            label_fontface = "plain",
                                            hjust = -2,
                                            ncol = 2))

# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_betabinom_reduced_effect_size_panels_vert.eps"),
#           nuuk_reduced_effectsize_plot_grid_ver, base_height = 15, base_aspect_ratio = 0.8)

# 2x3 grid (horizontal layout)
(nuuk_effectsize_plot_grid_hor <- plot_grid(effect_size_plot.BetNan, 
                                            effect_size_plot.EmpNig, 
                                            effect_size_plot.RhoGro, 
                                            effect_size_plot.SalGla, 
                                            effect_size_plot.VacUli,
                                            labels = c("a)", "b)", "c)", "d)", "e)"),
                                            label_size = 20,
                                            label_fontface = "plain",
                                            hjust = -2,
                                            ncol = 3))

# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_betabinom_effect_size_panels_hor.eps"),
#           nuuk_effectsize_plot_grid_hor, base_height = 10, base_aspect_ratio = 1.5)

# 2x3 grid reduced predictor terms
(nuuk_reduced_effectsize_plot_grid_hor <- plot_grid(effect_size_plot.BetNan2, 
                                            effect_size_plot.EmpNig2, 
                                            effect_size_plot.RhoGro2, 
                                            effect_size_plot.SalGla2, 
                                            effect_size_plot.VacUli2,
                                            labels = c("a)", "b)", "c)", "d)", "e)"),
                                            label_size = 20,
                                            label_fontface = "plain",
                                            hjust = -2,
                                            ncol = 3))

# save plot
# save_plot(file.path("..", "figures", "nuuk_shrub_drivers_betabinom_reduced_effect_size_panels_hor.eps"),
#           nuuk_reduced_effectsize_plot_grid_hor, base_height = 10, base_aspect_ratio = 1.5)

Graphs

Betula nana - temperature variability

Salix glauca - competition


unique.compet <- seq(min(SalGla.tot$competC), max(SalGla.tot$competC), by = 0.02) 

preds.compet.SalGla <- array(dim=c(length(unique.compet), 
                                     nrow(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list$b_plotgroup)))

for (i in 1:length(unique.compet)){
  preds.compet.SalGla[i,] <- plogis(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list$b.compet[,1]*unique.compet[i])
}

# # preds.continent1biome2 <- array(dim=c(length(unique.compet), 
# #                                       length(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list$b1meanForest[,1])))
# # 
# # for (i in 1:length(unique.compet)){
# #   preds.continent1biome2[i,] <- plogis(model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list$b1meanSavanna + model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list$brain.x[,2]*unique.compet[i] + model_out.shrub_gradient.SalGla2$BUGSoutput$sims.list$brain.x2[,2]*(unique.compet[i]^2))}


# # continentpreds <- array(c(preds.continent1biome1,preds.continent1biome2), dim=c(length(unique.compet), ncol(preds.continent1biome1),2))

preds.compet.SalGla[1:10,1:10] # [compet,sims]

quantiles.compet.SalGla <- array(NA, dim=c(length(unique.compet),5))


for (i in 1:length(unique.compet)){#compet
  #i<-1
    quantiles.compet.SalGla[i,]<-quantile(preds.compet.SalGla[i,], c(0.025, 0.25, 0.5, 0.95, 0.975))
}

quantiles.compet.SalGla[1:5,1:5]

predsmatrix.compet.SalGla <- data.frame(expand.grid(competC=c(unique.compet)))
predsmatrix.compet.SalGla$l95CI<-rep(NA, nrow(predsmatrix.compet.SalGla))
predsmatrix.compet.SalGla$l90CI<-rep(NA, nrow(predsmatrix.compet.SalGla))
predsmatrix.compet.SalGla$med<-rep(NA, nrow(predsmatrix.compet.SalGla))
predsmatrix.compet.SalGla$u90CI<-rep(NA, nrow(predsmatrix.compet.SalGla))
predsmatrix.compet.SalGla$u95CI<-rep(NA, nrow(predsmatrix.compet.SalGla)) 

head(predsmatrix.compet.SalGla)

# # rainfallseq<-rep(1:length(unique.compet),each=2)

for (i in 1:nrow(predsmatrix.compet.SalGla)){
  predsmatrix.compet.SalGla[i,c(2:6)] <- quantiles.compet.SalGla[i,]
}

predsmatrix.compet.SalGla$compet <- predsmatrix.compet.SalGla$competC + attr(scale(SalGla.tot$compet), 'scaled:center')

(pred_plot.compet.SalGla <- ggplot() +
  # competition is modeled on plot level, so use input data as is
  geom_point(data = SalGla.tot, 
             aes(x = compet, 
                 y = cover), 
             size = 2,
             position = position_jitter(width=0, height=.01),
             alpha = 0.5) +
  
  # plot line of predicted median values
  geom_line(data = predsmatrix.compet.SalGla, 
            aes(x = compet, 
                y = med), 
            colour = "orange",
            alpha = 1,
            size = 3) + 
  # scale_colour_manual(values=c("darkgreen","orange","darkgreen","orange"),name="Biome") +
  
  # plot predicted 95% CI
  geom_ribbon(data = predsmatrix.compet.SalGla,
                aes(x = compet, 
                  ymin = l95CI, 
                  ymax = u95CI),
              fill = "orange",
              alpha = 0.2) +
  # plot predicted 90% CI
  geom_ribbon(data = predsmatrix.compet.SalGla,
                aes(x = compet, 
                  ymin = l90CI, 
                  ymax = u90CI),
              fill = "orange",
              alpha = 0.4) +
  # scale_fill_manual(values=c("darkgreen","orange"),name="Biome") +
  labs(x = "summed abundance of taller-growing species per plot",
       y = "rel. no. hits per plot") + 
  theme_bw())

looks weird; prediction does not relate to data points in x or y range.

Check predicted values

Let’s run another model with some derived values to see if we get the same numbers out as the way we have extracted them above (i.e., by scaling back). That will tell us whether it’s a problem with the back-scaling or a more fundamental issue.

# assemble data: SalGla as example ----
shrub_gradient_jags.SalGla.xhat.data <- list(
  
  # plot level predictors, for discrete...
  cov.dis = SalGla.dis$cover,
  plotgroup.dis = SalGla.dis$plotgroup.NUM, #AB added this
  # isocline.dis = SalGla.dis$site_alt.NUM,
  # inclin_down.dis = SalGla.dis$inclin_downC,
  sri.dis = SalGla.dis$sriC,
  tri.dis = SalGla.dis$triC,
  twi.dis = SalGla.dis$twiC,
  compet.dis = SalGla.dis$competC,
  N_discrete = nrow(SalGla.dis),
  
  # ...and continuous part of the data
  cov.cont = SalGla.cont$cover,
  plotgroup.cont = SalGla.cont$plotgroup.NUM, #AB added this
  # isocline.cont = SalGla.cont$site_alt.NUM,
  # inclin_down.cont = SalGla.cont$inclin_downC,
  sri.cont = SalGla.cont$sriC,
  tri.cont = SalGla.cont$triC,
  twi.cont = SalGla.cont$twiC,
  compet.cont = SalGla.cont$competC,
  N_cont = nrow(SalGla.cont),
  
  # plot group level predictors
  tempjja.tot = SalGla.tot$tempjja_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)], # one value per tXpg
  # tempmax.tot = SalGla.tot$tempmax_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  # tempmin.tot = SalGla.tot$tempmin_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  tempcont.tot = SalGla.tot$tempcont_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  precipjja.tot = SalGla.tot$precipjja_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)],
  # precipjfmam.tot = SalGla.tot$precipjfmam_ts_30C[!duplicated(SalGla.tot$plotgroup.NUM)]
  N_plotgroups = length(unique(SalGla.tot$site_alt_plotgroup_id)),
  
  xhat = seq(from = min(SalGla.tot$tempcont_ts_30C), to = max(SalGla.tot$tempcont_ts_30C), length.out = 100),
  Nxhat = 100
  # # site/alt level predictors
  # alt.tot = SalGla.tot$altC[!duplicated(SalGla.tot$site_alt.NUM)],
  # N_isoclines = length(unique(SalGla.tot$site_alt_id))
)
str(shrub_gradient_jags.SalGla.xhat.data)

We’ll add some predicted values (phat) to the model:

Specify the parameters to be monitored:

Run model:

Extract coefficients and make graph of data and prediction curve:

# extract coefficients 
coeff.shrub_gradient.SalGla2.xhat <- model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.SalGla2.xhat),"[[]",fixed=FALSE), "[", 1))) #%>% print

# # add 90% CIs
# ci_90.SalGla2.xhat <- data.frame(q5 = NA, 
#                                  q95 = NA, 
#                                  param = NA)
# for (param in 1:(length(model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$sims.list))){
#   ci_90.SalGla2.xhat[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$sims.list[param])[,1], 
#                                             probs = c(0.05, 0.95))
#   ci_90.SalGla2.xhat[param, 3] <- names(data.frame(model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$sims.list))[param]
# }

# join to coefficients table
coeff.shrub_gradient.SalGla2.xhat <- coeff.shrub_gradient.SalGla2.xhat %>% 
  # left_join(ci_90.SalGla2.xhat, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         # l90 = q5,
         # u90 = q95,
         u95 = "97.5%",
         Rhat) # %>% print

# assemble predicted and predictor values
phats <- coeff.shrub_gradient.SalGla2.xhat %>% 
  
  # filter for predicted values
  filter(param %in% c(paste0("phat[", seq(from = 1, to = 100), "]"))) %>% 
  
  # add xhats column
  mutate(xhats = seq(from = min(SalGla.tot$tempcont_ts_30C),
                     to = max(SalGla.tot$tempcont_ts_30C),
                     length.out = 100))
  
# back-center and back-scale predictor values (xhats)

phats$tempcont <- phats$xhats*attr(scale(SalGla.tot$tempcont_ts_30), 'scaled:scale') + attr(scale(SalGla.tot$tempcont_ts_30), 'scaled:center') 

ggplot() +
  # tempcont is modelled at plotgroup level, so reduce base data (points layer) to plotgroup level
  geom_point(data = SalGla.tot %>% group_by(site_alt_plotgroup_id) %>% summarise(tempcont = mean(tempcont_ts_30), cover = mean(cover)), 
             aes(x = tempcont, 
                 y = cover), 
             size = 2,
             position = position_jitter(width=0, height=.01),
             alpha=0.5) +
  
  # draw line of predicted values
  geom_line(data = phats, 
            aes(x = tempcont, 
                y = plogis(mean)), 
            colour = "orange",
            alpha = 1,
            size = 3) + 
  # scale_colour_manual(values=c("darkgreen","orange","darkgreen","orange"),name="Biome") +
  
  # draw predicted 95% CI
  geom_ribbon(data = phats,
              aes(x = tempcont, 
                  ymin = plogis(l95), 
                  ymax = plogis(u95)),
              fill = "orange",
              alpha = 0.2) +
  
  # draw predicted 90% CI
  # geom_ribbon(data = phats,
  #               aes(x = tempcont,
  #                 ymin = plogis(l90),
  #                 ymax = plogis(u90)),
  #             fill = "orange",
  #             alpha = 0.4) +
  # scale_fill_manual(values=c("darkgreen","orange"),name="Biome") +
  labs(x = "annual temperature variability [°C]",
       y = "rel. no. hits per plot") + 
  theme_bw()

Extract coefficients and plot effect sizes:

# load model object
load(file = file.path("..", "data", "processed", "model_output_SalGla2_with_derived_values.RData"))
# extract coefficients 
coeff.shrub_gradient.SalGla2.xhat <- model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$summary %>% 
  as.data.frame %>% 
  select('mean','sd','2.5%','97.5%','Rhat') %>% 
# add identifying info to data frame
  rownames_to_column(var = "param")
  # mutate(param = as.vector(sapply(strsplit(rownames(coeff.shrub_gradient.SalGla),"[[]",fixed=FALSE), "[", 1))) #%>% print

# add 90% CIs
ci_90.SalGla2.xhat <- data.frame(q5 = NA, q95 = NA, param = NA)
for (param in 1:(length(model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$sims.list)-4)){
  ci_90.SalGla2.xhat[param,1:2] <- quantile(data.frame(model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$sims.list[param])[,1], probs = c(0.05, 0.95))
  ci_90.SalGla2.xhat[param, 3] <- names(data.frame(model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$sims.list))[param]
}

# join to coefficients table
coeff.shrub_gradient.SalGla2.xhat <- coeff.shrub_gradient.SalGla2.xhat %>% 
  left_join(ci_90.SalGla2.xhat, by = "param") %>% 
  # reorder and rename cols
  select(param, mean, sd, 
         l95 = "2.5%",
         l90 = q5,
         u90 = q95,
         u95 = "97.5%",
         Rhat) %>% print

# effect size plot
(effect_size_plot.SalGla2.xhat <- model_plot_sig_function(coeff.shrub_gradient.SalGla2.xhat, title_string = "Salix glauca", plot_width = 11))

extract predicted values:

# get statistical summary
model_xhat.out.df <- as.data.frame(model_out.shrub_gradient.SalGla2.xhat$BUGSoutput$summary[,c('mean','sd','2.5%','97.5%','n.eff','Rhat')])

model_xhat.out.df$Param <- sapply(strsplit(rownames(model_xhat.out.df), "[[]", fixed=F),"[",1)

p.out <- model_xhat.out.df[model_xhat.out.df$Param=="phat",]
p.out$xhat <- shrub_gradient_jags.SalGla.xhat.data$xhat #add the "x" values you used to predict phats

plot along with back-scaled values:

pred_plot.compet.SalGla +
   geom_line(data = p.out, 
            aes(x = xhat, 
                y = mean), 
            colour = "darkgreen",
            alpha = 1,
            size = 2) +
  geom_ribbon(data = p.out,
              aes(x = xhat,
                  ymin = `2.5%`, 
                  ymax = `97.5%`), 
              alpha = 0.3, 
              fill = "green")

———-

Save / load workspace image

# save.image(file = file.path("..", "data", "processed", "nuuk_shrub_drivers_output_nonsigx2removed.RData"))

# load ws for further analyses/plotting etc)
# load(file.path("data", "processed", "nuuk_shrub_drivers_output_nonsigx2removed.RData"))
LS0tDQp0aXRsZTogJ051dWsgRmpvcmQ6IERyaXZlcnMgb2Ygc2hydWIgYWJ1bmRhbmNlIC0gYmV0YS1iaW5vbWlhbCBtaXh0dXJlICBtb2RlbCwgc2VwYXJhdGVkIGJ5IHNwZWNpZXMnDQphdXRob3I6ICJKb25hdGhhbiB2b24gT3BwZW4iDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge3J9DQpybShsaXN0ID0gbHMoKSkNCmBgYA0KDQoNCiMjIERlcGVuZGVuY2llcw0KUGFja2FnZXMgaW5jbHVkZWQ6DQoNCiogdGlkeXZlcnNlIC0gZm9yIGNvbnZlbmllbnQgY29kZSBmbG93LCBkYXRhIHdyYW5nbGluZyBhbmQgcGxvdHRpbmcNCiogcmphZ3MgJiBSMmphZ3MgLSB0byBsaW5rIEpBR1MgYW5kIFINCiogc2tpbXIgLSBmb3IgZGF0YSBzdW1tYXJ5DQoqIGNvcnJyIC0gdG8gb3V0cHV0IGNvcnJlbGF0aW9uIG1hdHJpY2VzIGluIGRhdGFmcmFtZSBmb3JtYXQNCiogY293cGxvdCAmIHBhdGNod29yayAtIHRvIGNvbWJpbmUgcGxvdCBwYW5lbHMNCiogUm1hcmtkb3duIC0gdG8gcHJvZHVjZSB0aGlzIG5lYXQgbGl0dGxlIGRvY3VtZW50YXRpb24NCmBgYHtyIHNldHVwLCBtZXNzYWdlID0gRkFMU0V9DQojIGxvYWQgcGFjbWFuIHBhY2thZ2UgZnJvbSB0aGUgcmVwb3NpdG9yeSwgaWYgeW91IGRvIG5vdCBhbHJlYWR5IGhhdmUgaXQNCmlmICghcmVxdWlyZSgncGFjbWFuJykpIGluc3RhbGwucGFja2FnZXMoJ3BhY21hbicsIHJlcG9zPSJodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmciKQ0KcGFjbWFuOjpwX2xvYWQodGlkeXZlcnNlLCAjIHNldCBvZiBwYWNrYWdlcyBmb3IgZGF0YSBtYW5pcHVsYXRpb24sIGV4cGxvcmF0aW9uIGFuZCB2aXN1YWxpc2F0aW9uDQogICAgICAgICAgICAgICByamFncywgICAgICMgdG8gbGluayBKQUdTIGFuZCBSDQogICAgICAgICAgICAgICBSMmphZ3MsICAgICMgdG8gbGluayBKQUdTIGFuZCBSDQogICAgICAgICAgICAgICBza2ltciwgICAgICMgZm9yIHF1aWNrIGRhdGFmcmFtZSBpbnNwZWN0aW9uDQogICAgICAgICAgICAgICBjb3JyciwgICAgICMgb3V0cHV0IGNvcnJlbGF0aW9uIG1hdHJpY2VzIGFzIGRhdGEgZnJhbWUNCiAgICAgICAgICAgICAgIGNvd3Bsb3QsICAgIyBjb21iaW5lIHBsb3QgcGFuZWxzDQogICAgICAgICAgICAgICBwYXRjaHdvcmssICMgLSItDQogICAgICAgICAgICAgICBybWFya2Rvd24pICMgZm9yIFIgTWFya2Rvd24gZm9ybWF0dGluZw0KYGBgDQoNCkZ1bmN0aW9ucyB1c2VkOiANCg0KKiBwcmVkaWN0b3IgeCBzcGVjaWVzIGNvdmVyIHBsb3QgZ3JpZCBmdW5jdGlvbg0KKiBlZmZlY3Qgc2l6ZSBwbG90IGZ1bmN0aW9uDQpgYGB7cn0NCiMgY292ZXIgcGxvdCBncmlkcyAtLS0tDQpwcmVkLnBsb3QuZ3JpZCA8LSBmdW5jdGlvbihkZil7DQogIA0KICB0YXhhIDwtIGRmICU+JSBwdWxsKHRheG9uKSAlPiUgdW5pcXVlKCkgJT4lIGFzLmNoYXJhY3RlcigpDQogIA0KICBmb3IodGF4b25fbnIgaW4gMTpsZW5ndGgodGF4YSkpew0KICAgIHBsb3QgPC0gZ2dwbG90KGRhdGEgPSBkZiAlPiUgZmlsdGVyKHRheG9uID09IHRheGFbdGF4b25fbnJdKSwgDQogICAgICAgICAgICAgICAgICAgYWVzKHkgPSBjb3ZlciwgZ3JvdXAgPSB0YXhvbikpICsNCiAgICAgIGdlb21fcG9pbnQoYWVzKHggPSBwcmVkX3ZhbHVlKSwgY29sb3VyID0gImRhcmtncmV5IikgKw0KICAgICAgZ2VvbV9zbW9vdGgoYWVzKHggPSBwcmVkX3ZhbHVlKSwgbWV0aG9kID0gImxtIiwgY29sb3VyID0gImRhcmtncmVlbiIsIHNlID0gVFJVRSwgbmEucm0gPSBUUlVFKSArDQogICAgICBnZW9tX3Ntb290aChhZXMoeCA9IHByZWRfdmFsdWUpLCBtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHBvbHkoeCwgMiksIGNvbG91ciA9ICJkYXJrb3JhbmdlIiwgc2UgPSBUUlVFLCBuYS5ybSA9IFRSVUUpICsNCiAgICAgIGZhY2V0X3dyYXAofnByZWRpY3Rvciwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gNCkgKw0KICAgICAgc2NhbGVfeV9jb250aW51b3VzKCJyZWxhdGl2ZSBuby4gcGluIGhpdHMgcGVyIHBsb3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgbWF4KGRmICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih0YXhvbiA9PSB0YXhhW3RheG9uX25yXSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVsbChjb3ZlcikpKSkgKw0KICAgICAgbGFicyh4ID0gInByZWRpY3RvciB2YWx1ZSIpICsNCiAgICAgIGdndGl0bGUocGFzdGUwKHRheGFbdGF4b25fbnJdLCAiIGNvdmVyIH4gcHJlZGljdG9ycyIpKSArDQogICAgICB0aGVtZV9idygpICsNCiAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCiAgICBwcmludChwbG90KQ0KICB9DQp9DQoNCiMgZWZmZWN0IHNpemUgcGxvdHMgLS0tLQ0KIyBmb3IgY2FzZXMgd2l0aCBvbmx5ICdzaWduaWZpY2FudCcgZWZmZWN0cw0KbW9kZWxfcGxvdF9zaWdfZnVuY3Rpb24gPC0gZnVuY3Rpb24obW9kZWxfY29lZmZfb3V0cHV0LCB0aXRsZV9zdHJpbmcsIHBsb3Rfd2lkdGgpIHsNCiAgdGFyZ2V0X3ZhcnMgPC0gYygiYi50ZW1wamphLngiLCAiYi50ZW1wamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgImIudGVtcGNvbnQueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgImIucHJlY2lwamphLngyIiwNCiAgICAgICAgICAgICAgICAgICAiYi5zcmkiLA0KICAgICAgICAgICAgICAgICAgICJiLnRyaSIsDQogICAgICAgICAgICAgICAgICAgImIudHdpIiwgDQogICAgICAgICAgICAgICAgICAgImIuY29tcGV0IikNCiAgc29sdXRpb25zIDwtIG1vZGVsX2NvZWZmX291dHB1dA0KICBuYW1lcyhzb2x1dGlvbnMpIDwtIGMoInZhcmlhYmxlIiwgInBvc3QubWVhbiIsICJwb3N0LnNkIiwgImw5NSIsICJsOTAiLCAidTkwIiwgInU5NSIsICJSaGF0IikNCiAgc29sdXRpb25zIDwtIHNvbHV0aW9ucyAlPiUgDQogICAgZmlsdGVyKHZhcmlhYmxlICVpbiUgdGFyZ2V0X3ZhcnMpDQogICMgc29sdXRpb25zJHZhcmlhYmxlIDwtIGZhY3Rvcihzb2x1dGlvbnMkdmFyaWFibGUsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiYi50ZW1wamphLngiLCAiYi50ZW1wamphLngyIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLnRlbXBjb250LngiLCAiYi50ZW1wY29udC54MiIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi5wcmVjaXBqamEueCIsICJiLnByZWNpcGpqYS54MiIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi5zcmkiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLnR3aSIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiKSkNCiAgbWluX3ZhbHVlIDwtIGZsb29yKG1pbihzb2x1dGlvbnMkbDk1KSkNCiAgbWF4X3ZhbHVlIDwtIGNlaWxpbmcobWF4KHNvbHV0aW9ucyR1OTUpKQ0KICBzb2x1dGlvbnMkc2lnIDwtICJucyINCiAgc29sdXRpb25zJHNpZ1tzb2x1dGlvbnMkbDk1IDwgMCAmIHNvbHV0aW9ucyR1OTUgPCAwXSA8LSAic2lnIg0KICBzb2x1dGlvbnMkc2lnW3NvbHV0aW9ucyRsOTUgPiAwICYgc29sdXRpb25zJHU5NSA+IDBdIDwtICJzaWciDQogIGxhYmVsX2NvbG91ciA8LSByZXAoImJsYWNrIiwgbnJvdyhzb2x1dGlvbnMpKQ0KICBsYWJlbF9jb2xvdXJbc29sdXRpb25zJHNpZyA9PSAic2lnIl0gPC0gdGhlbWVfZGFya2dyZWVuDQogIGxhYmVsX2ZhY2UgPC0gcmVwKCJwbGFpbiIsIG5yb3coc29sdXRpb25zKSkNCiAgbGFiZWxfZmFjZVtzb2x1dGlvbnMkc2lnID09ICJzaWciXSA8LSAiYm9sZCINCiAgIyBsYWJlbF9mYWNlW3Jlc3BvbnNlID09ICJUMV9tZWFuIiAmIHNvbHV0aW9ucyRzaWcgPT0gInNpZyJdIDwtICJib2xkIg0KICB0aXRsZV9zdHJpbmcgPC0gdGl0bGVfc3RyaW5nDQogIHRpdGxlX2NvbG91ciA8LSAiZ3JleTEwIg0KICAjIGlmKHJlc3BvbnNlID09ICJUMV9tZWFuIiB8IHJlc3BvbnNlID09ICJUMV9hbXAiKSB0aXRsZV9jb2xvdXIgPC0gdGhlbWVfcmVkDQogICMgaWYocmVzcG9uc2UgPT0gIlQyX21lYW4iIHwgcmVzcG9uc2UgPT0gIlQyX2FtcCIpIHRpdGxlX2NvbG91ciA8LSB0aGVtZV95ZWxsb3cNCiAgIyBpZihyZXNwb25zZSA9PSAiVDFfbWVhbiIpIHJlc3BvbnNlIDwtICJTb2lsIg0KICAjIGlmKHJlc3BvbnNlID09ICJUMl9tZWFuIikgcmVzcG9uc2UgPC0gIkdyb3VuZCINCiAgDQogIA0KICBtb2RlbF9wbG90X3NpZyA8LSBnZ3Bsb3Qoc29sdXRpb25zLCBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gcG9zdC5tZWFuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluID0gbDk1LCB5bWF4ID0gdTk1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzaWcpKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBnZW9tX2Vycm9yYmFyKHdpZHRoID0gLjgpICsNCiAgICB0aGVtZV9jb3dwbG90KDE4KSArDQogICAgeWxhYigiRWZmZWN0IFNpemUgKHNjYWxlZCkiKSArDQogICAgeGxhYigiIikgKw0KICAgIGdndGl0bGUocGFzdGUwKHRpdGxlX3N0cmluZykpICsNCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgdGhlbWVfZGFya2dyZWVuKSkgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKG1pbl92YWx1ZSwgbWF4X3ZhbHVlKSwgYnJlYWtzID0gc2VxKG1pbl92YWx1ZSxtYXhfdmFsdWUsMC41KSkgKw0KICAgICMgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJiLnRlbXBqamEueCIsICJiLnRlbXBqamEueDIiLA0KICAgICMgICAgICAgICAiYi50ZW1wY29udC54IiwgImIudGVtcGNvbnQueDIiLA0KICAgICMgICAgICAgICAiYi5wcmVjaXBqamEueCIsICJiLnByZWNpcGpqYS54MiIsDQogICAgIyAgICAgICAgICJiLnNyaSIsDQogICAgIyAgICAgICAgICJiLnRyaSIsDQogICAgIyAgICAgICAgICJiLnR3aSIsDQogICAgIyAgICAgICAgICJiLmNvbXBldCIpLA0KICAgICMgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJzdW1tZXIgdGVtcGVyYXR1cmUiLCBicXVvdGUoLigic3VtbWVyIikgKiIgIiogdGVtcGVyYXR1cmVeMiksDQogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5IiwgYnF1b3RlKC4oInRlbXBlcmF0dXJlIikgKiIgIiogdmFyaWFiaWxpdHleMiksDQogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN1bW1lciBwcmVjaXBpdGF0aW9uIiwgYnF1b3RlKC4oInN1bW1lciIpICoiICIqIHByZWNpcGl0YXRpb25eMiksDQogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNvbGFyIHJhZGlhdGlvbiIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0ZXJyYWluIHJ1Z2dlZG5lc3MiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9pc3R1cmUgYXZhaWxhYmlsaXR5IiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbXBldGl0aW9uIikpICsNCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMCwgeGVuZCA9IHBsb3Rfd2lkdGgsIHkgPSAwLCB5ZW5kID0gMCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgY29sb3VyID0gbGFiZWxfY29sb3VyLCBmYWNlID0gbGFiZWxfZmFjZSksDQogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSB0aXRsZV9jb2xvdXIsIGZhY2UgPSAiaXRhbGljIiksDQogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KICByZXR1cm4obW9kZWxfcGxvdF9zaWcpDQp9DQoNCiMgZm9yIGNhc2VzIHdpdGggbWFyZ2luYWwgJ3NpZ25pZmljYW5jZScNCm1vZGVsX3Bsb3RfbWFyZ19mdW5jdGlvbiA8LSBmdW5jdGlvbihtb2RlbF9jb2VmZl9vdXRwdXQsIHRpdGxlX3N0cmluZywgcGxvdF93aWR0aCkgew0KICB0YXJnZXRfdmFycyA8LSBjKCJiLnRlbXBqamEueCIsICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLnRlbXBjb250LngiLCAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgImIucHJlY2lwamphLngiLCAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICJiLnNyaSIsDQogICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAiYi50d2kiLCANCiAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiKQ0KICBzb2x1dGlvbnMgPC0gbW9kZWxfY29lZmZfb3V0cHV0DQogIG5hbWVzKHNvbHV0aW9ucykgPC0gYygidmFyaWFibGUiLCAicG9zdC5tZWFuIiwgInBvc3Quc2QiLCAibDk1IiwgImw5MCIsICJ1OTAiLCAidTk1IiwgIlJoYXQiKQ0KICBzb2x1dGlvbnMgPC0gc29sdXRpb25zICU+JSANCiAgICBmaWx0ZXIodmFyaWFibGUgJWluJSB0YXJnZXRfdmFycykNCiAgIyBzb2x1dGlvbnMkdmFyaWFibGUgPC0gZmFjdG9yKHNvbHV0aW9ucyR2YXJpYWJsZSwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJiLnRlbXBqamEueCIsICJiLnRlbXBqamEueDIiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImIudGVtcGNvbnQueCIsICJiLnRlbXBjb250LngyIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgImIucHJlY2lwamphLngyIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLnNyaSIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYi50cmkiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImIudHdpIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiLmNvbXBldCIpKQ0KICBtaW5fdmFsdWUgPC0gZmxvb3IobWluKHNvbHV0aW9ucyRsOTUpKQ0KICBtYXhfdmFsdWUgPC0gY2VpbGluZyhtYXgoc29sdXRpb25zJHU5NSkpDQogIHNvbHV0aW9ucyRzaWcgPC0gIm5zIg0KICBzb2x1dGlvbnMkc2lnW3NvbHV0aW9ucyRsOTUgPCAwICYgc29sdXRpb25zJHU5NSA8IDBdIDwtICJzaWciDQogIHNvbHV0aW9ucyRzaWdbc29sdXRpb25zJGw5NSA+IDAgJiBzb2x1dGlvbnMkdTk1ID4gMF0gPC0gInNpZyINCiAgc29sdXRpb25zJHNpZ1tzb2x1dGlvbnMkbDkwIDwgMCAmIHNvbHV0aW9ucyR1OTAgPCAwICYgc29sdXRpb25zJGw5NSA8IDAgJiBzb2x1dGlvbnMkdTk1ID4gMF0gPC0gIm1hcmciDQogIHNvbHV0aW9ucyRzaWdbc29sdXRpb25zJGw5MCA+IDAgJiBzb2x1dGlvbnMkdTkwID4gMCAmIHNvbHV0aW9ucyRsOTUgPCAwICYgc29sdXRpb25zJHU5NSA+IDBdIDwtICJtYXJnIg0KICBsYWJlbF9jb2xvdXIgPC0gcmVwKCJibGFjayIsIG5yb3coc29sdXRpb25zKSkNCiAgbGFiZWxfY29sb3VyW3NvbHV0aW9ucyRzaWcgPT0gInNpZyJdIDwtIHRoZW1lX2RhcmtncmVlbg0KICBsYWJlbF9jb2xvdXJbc29sdXRpb25zJHNpZyA9PSAibWFyZyJdIDwtIHRoZW1lX3B1cnBsZQ0KICBsYWJlbF9mYWNlIDwtIHJlcCgicGxhaW4iLCBucm93KHNvbHV0aW9ucykpDQogIGxhYmVsX2ZhY2Vbc29sdXRpb25zJHNpZyA9PSAic2lnIl0gPC0gImJvbGQiDQogICMgbGFiZWxfZmFjZVtyZXNwb25zZSA9PSAiVDFfbWVhbiIgJiBzb2x1dGlvbnMkc2lnID09ICJzaWciXSA8LSAiYm9sZCINCiAgdGl0bGVfc3RyaW5nIDwtIHRpdGxlX3N0cmluZw0KICB0aXRsZV9jb2xvdXIgPC0gImdyZXkxMCINCiAgIyBpZihyZXNwb25zZSA9PSAiVDFfbWVhbiIgfCByZXNwb25zZSA9PSAiVDFfYW1wIikgdGl0bGVfY29sb3VyIDwtIHRoZW1lX3JlZA0KICAjIGlmKHJlc3BvbnNlID09ICJUMl9tZWFuIiB8IHJlc3BvbnNlID09ICJUMl9hbXAiKSB0aXRsZV9jb2xvdXIgPC0gdGhlbWVfeWVsbG93DQogICMgaWYocmVzcG9uc2UgPT0gIlQxX21lYW4iKSByZXNwb25zZSA8LSAiU29pbCINCiAgIyBpZihyZXNwb25zZSA9PSAiVDJfbWVhbiIpIHJlc3BvbnNlIDwtICJHcm91bmQiDQogIA0KICANCiAgbW9kZWxfcGxvdF9tYXJnIDwtIGdncGxvdChzb2x1dGlvbnMsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBwb3N0Lm1lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSBsOTUsIHltYXggPSB1OTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNpZykpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fZXJyb3JiYXIod2lkdGggPSAuOCkgKw0KICAgIHRoZW1lX2Nvd3Bsb3QoMTgpICsNCiAgICB5bGFiKCJFZmZlY3QgU2l6ZSAoc2NhbGVkKSIpICsNCiAgICB4bGFiKCIiKSArDQogICAgZ2d0aXRsZShwYXN0ZTAodGl0bGVfc3RyaW5nKSkgKyANCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGModGhlbWVfcHVycGxlLCAiYmxhY2siLCB0aGVtZV9kYXJrZ3JlZW4pKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMobWluX3ZhbHVlLCBtYXhfdmFsdWUpLCBicmVha3MgPSBzZXEobWluX3ZhbHVlLG1heF92YWx1ZSwwLjUpKSArDQogICAgIyBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICAgIyAgICAgICAgICJiLnRlbXBjb250LngiLCAiYi50ZW1wY29udC54MiIsDQogICAgIyAgICAgICAgICJiLnByZWNpcGpqYS54IiwgImIucHJlY2lwamphLngyIiwNCiAgICAjICAgICAgICAgImIuc3JpIiwNCiAgICAjICAgICAgICAgImIudHJpIiwNCiAgICAjICAgICAgICAgImIudHdpIiwNCiAgICAjICAgICAgICAgImIuY29tcGV0IiksDQogICAgIyAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInN1bW1lciB0ZW1wZXJhdHVyZSIsIGJxdW90ZSguKCJzdW1tZXIiKSAqIiAiKiB0ZW1wZXJhdHVyZV4yKSwNCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkiLCBicXVvdGUoLigidGVtcGVyYXR1cmUiKSAqIiAiKiB2YXJpYWJpbGl0eV4yKSwNCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3VtbWVyIHByZWNpcGl0YXRpb24iLCBicXVvdGUoLigic3VtbWVyIikgKiIgIiogcHJlY2lwaXRhdGlvbl4yKSwNCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic29sYXIgcmFkaWF0aW9uIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRlcnJhaW4gcnVnZ2VkbmVzcyIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb2lzdHVyZSBhdmFpbGFiaWxpdHkiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29tcGV0aXRpb24iKSkgKw0KICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAwLCB4ZW5kID0gcGxvdF93aWR0aCwgeSA9IDAsIHllbmQgPSAwKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBjb2xvdXIgPSBsYWJlbF9jb2xvdXIsIGZhY2UgPSBsYWJlbF9mYWNlKSwNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IHRpdGxlX2NvbG91ciwgZmFjZSA9ICJpdGFsaWMiKSwNCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQogIHJldHVybihtb2RlbF9wbG90X21hcmcpDQp9DQoNCmBgYA0KDQpDb2xvdXIgc2NoZW1lOg0KYGBge3J9DQojIENvbG91ciBzY2hlbWUgIyMjIw0KdGhlbWVfcmVkIDwtICIjRTY0NDQ3RkYiDQp0aGVtZV9ibHVlIDwtICIjMTI0MzVERkYiDQp0aGVtZV9saWdodGJsdWUgPC0gIiMxRkEzQUVGRiINCnRoZW1lX2dyZXkgPC0gIiNFREVERURGRiINCnRoZW1lX3llbGxvdyA8LSAiI0VFQkU1QkZGIg0KDQojIGFkZGl0aW9uYWwgY29sb3Vycw0KdGhlbWVfZGFya2JsdWUgPC0gIiMxRDU3OTkiDQp0aGVtZV9kYXJrZ3JlZW4gPC0gIiMxMzk0NEQiDQp0aGVtZV9vcmFuZ2UgPC0gIiNCNTZBMjQiDQp0aGVtZV9wdXJwbGUgPC0gIiM4NzU3QjMiDQpgYGANCg0KIyMgU2luZ2xlLXNwZWNpZXMgbW9kZWxzDQoNClRoaXMgZGF0YXNldCBpcyBhIG5ldyBvbmUgY29udGFpbmluZyBwcmVkaWN0b3JzIGV4dHJhY3RlZCBmcm9tIGRvd25zY2FsZWQgQ0hFTFNBIGNsaW1hdGUgZGF0YS4NCg0KQW5hbHlzZXMgY29uZHVjdGVkIG9uIGZ1c2lvbiB0YWJsZSBhdCAqKnBsb3QgJFx0aW1lcyQgdGF4b24gbGV2ZWwqKiAoYXMgd2UgYXJlIGV4cGxpY2l0bHkgaW50ZXJlc3RlZCBpbiBwbG90LWxldmVsIHZhcmlhdGlvbiBvZiBwcmVkaWN0b3JzLCBlc3AuIHNsb3BlLCBzb2xhciByYWRpYXRpb24sIHRlcnJhaW4gcnVnZ2VkbmVzcywgdG9wb2dyYXBoaWNhbCB3ZXRuZXNzLCBhbmQgY29tcGV0aXRpb24pOiAzNzI2IG9ic2VydmF0aW9ucyBmb3IgMzggdmFyaWFibGVzDQoNCmBgYHtyfQ0KZW52X2Nvdl9iaW8gPC0gcmVhZC5jc3YoIi4uL2RhdGEvbnV1a19lbnZfY292ZXJfcGxvdHMuY3N2IiwgaGVhZGVyID0gVCkgJT4lIA0KICAjIHJlbmFtZSB2YXJpYWJsZSAidHdpXzkwbSIgdG8gInR3aSINCiAgcmVuYW1lKHR3aSA9IHR3aV85MG0pDQpgYGANCjwhLS0gPGJ1dHRvbiBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGRhdGEtdGFyZ2V0PSIjQmxvY2tOYW1lIj4gU2hvdy9IaWRlIERhdGEgU3VtbWFyeSA8L2J1dHRvbj4gLS0+DQo8IS0tIDxkaXYgaWQ9IkJsb2NrTmFtZSIgY2xhc3M9ImNvbGxhcHNlIj4gLS0+DQo8IS0tIGBgYHtyfSAtLT4NCjwhLS0gc2tpbShlbnZfY292X2JpbykgLS0+DQo8IS0tIGBgYCAtLT4NCg0KDQojIyMgUHJlcGFyZSBkYXRhIGZvciBKQUdTIG1vZGVsIA0KIyMjIGEpIHNlbGVjdGlvbiBvZiB2YXJpYWJsZXMgcmVsZXZhbnQgZm9yIGFuYWx5c2lzDQppbmNsdWRpbmcgcHJlZGljdG9ycw0KDQoqIEluZm9ybWF0aW9uIG9uIHNpdGUsIHBsb3QsIHBsb3QgZ3JvdXAsIHNhbXBsaW5nIGxvY2F0aW9uIChsYXQsIGxvbiwgYWx0aXR1ZGUpLCBzYW1wbGluZyB5ZWFyIA0KKiBkb3duc2NhbGVkIENIRUxTQSBwcmVkaWN0b3JzLCBhdmVyYWdlZCBvdmVyIGEgMzAteWVhciBwZXJpb2QgKCpbLi4uXV90c18zMCopIA0KKiBzb2xhciByYWRpYXRpb24gaW5kZXggKFNSSSwgZm9sbG93aW5nIFtLZWF0aW5nIGV0IGFsLiAyMDA3XShodHRwOi8vd3d3LmJpb29uZS5vcmcvZG9pL2Ficy8xMC4yMTkzLzIwMDYtMzU5KSksIHNsb3BlIChlcm9zaW9uIG1lYXN1cmUpLCBUZXJyYWluIFJ1Z2dlZG5lc3MgSW5kZXggKFRSSSwgZm9sbG93aW5nIFtSaWxleSBldCBhbC4gMTk5OV0oaHR0cDovL2Rvd25sb2FkLm9zZ2VvLm9yZy9xZ2lzL2RvYy9yZWZlcmVuY2UtZG9jcy9UZXJyYWluX1J1Z2dlZG5lc3NfSW5kZXgucGRmKSksIE5vcm1hbGlzZWQgRGlmZmVyZW5jZSBXZXRuZXNzIEluZGV4IChORFdJLCBbR2FvIDE5OTZdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzAwMzQ0MjU3OTYwMDA2NzMpKSwgVGFzc2VsZWQgQ2FwIFdldG5lc3MgSW5kZXggKFRDV0ksIFtDcmlzdCAmIENpY2NvbmUgMTk4NF0oaHR0cHM6Ly9pZWVleHBsb3JlLmllZWUub3JnL2RvY3VtZW50LzQxNTc1MDcpKSwgU0FHQSBUb3BvZ3JhcGhpYyBXZXRuZXNzIEluZGV4IChUV0ksIHNlZSBbQ29ucmFkIGV0IGFsLiAyMDE1XShodHRwczovL2dtZC5jb3Blcm5pY3VzLm9yZy9hcnRpY2xlcy84LzE5OTEvMjAxNS8pIGFuZCB0aGUgW2luZGV4IGRvY3VtZW50YXRpb25dKGh0dHA6Ly93d3cuc2FnYS1naXMub3JnL3NhZ2FfdG9vbF9kb2MvMi4yLjIvdGFfaHlkcm9sb2d5XzE1Lmh0bWwpKQ0KKiB0YXhvbiAoc2VlIGFib3ZlIGZvciBsZXZlbHMpDQoqIGNvbXBldGl0aW9uIHByZXNzdXJlIGluIHRoZSBjb21tdW5pdHkgKGFzIHN1bW1lZCBhYnVuZGFuY2Ugb2YgdGFsbGVyLWdyb3dpbmcgc2hydWIgc3BlY2llcyB3aXRoaW4gYSBwbG90LCBhdmVyYWdlZCB3aXRoaW4gcGxvdCBncm91cHMpDQoNCmFuZCByZXNwb25zZSB2YXJpYWJsZSANCg0KKiBjb3ZlciAoYXMgcmVsYXRpdmUgbm8uIGhpdHMgcGVyIHBsb3QgZm9yIGVhY2ggc3BlY2llcykNCmBgYHtyfQ0KZW52X2Nvdl9iaW9fc3ViIDwtIGVudl9jb3ZfYmlvICU+JSANCiAgc2VsZWN0KHNpdGVfYWx0X3Bsb3Rncm91cF9pZCwgcGxvdCwgc2l0ZSwgc2l0ZV9hbHRfaWQsIHllYXIsIGxvbmcsIGxhdCwgYWx0LCAgIyBwbG90IGluZm8gLyBtZXRhZGF0YQ0KICBlbmRzX3dpdGgoIl90c18zMCIpLCAgICMgQ0hFTFNBIHByZWRpY3RvcnMgYXZlcmFnZWQgb3ZlciAxMC15ZWFyIHBlcmlvZCBwcmlvciB0byBzdHVkeSB5ZWFyDQogIGluY2xpbl9kb3duLCB0d2ksIHRyaSwgc3JpLCANCiAgI21lYW5fc3VtbV9uZHZpX3lvcywgY3ZfbWVhbl9zdW1tX25kdmlfMjAwMV90b195b3MsIFBlcmNfZGlzdF9jb2FzdF9saW5lcywgICAjIGVudmlyb25tZW50YWwgZGF0YQ0KICB0YXhvbiwgY292ZXIsIGNvbXBldCkgICAjIHRheG9uLCBjb3ZlciByZXNwb25zZSwgY29tcGV0aXRpb24gcHJlc3N1cmUNCmhlYWQoZW52X2Nvdl9iaW9fc3ViKQ0KYGBgDQoNCkxldCdzIGNoZWNrIGZvciBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgbW9pc3R1cmUgcHJlZGljdG9ycyBhbmQgdGVycmFpbiBydWdnZWRuZXNzOg0KDQpgYGB7cn0NCihjb3JfbW9pc3QgPC0gZW52X2Nvdl9iaW8gJT4lIA0KICBzZWxlY3QodHdpLCBuZHdpLCB0Y3dzLCB0cmkpKSAlPiUgDQogIGNvcnJlbGF0ZShkaWFnb25hbCA9IDEpDQpgYGANCiRcUmlnaHRhcnJvdyQgTkRXSSBhbmQgVENXUyBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQsIGJ1dCBib3RoIGFyZSBsYXJnZWx5IGluZGVwZW5kZW50IGZyb20gVFdJIGFuZCBUUkkuDQpXZSdsbCBnbyB3aXRoIFRXSSBmb3Igbm93LCBhcyBpdCBpcyBsZWFzdCBjb25mb3VuZGVkIGJ5IHZlZ2V0YXRpb24sIGJ1dCB3aWxsIGhhdmUgdG8gZGlzY3VzcyBtYXliZSBpbmNsdWRpbmcgYSBzZWNvbmQgaW5kZXgsIGRlcGVuZGluZyBvbiBoeXBvdGhlc2lzL2Vjb2xvZ2ljYWwgaW1wbGljYXRpb24uDQoNCjxicj4NCg0KUHJlZGljdG9ycyBkb24ndCBhbHdheXMgdmFyeSBiZXR3ZWVuIHBsb3RzIHdpdGhpbiBwbG90Z3JvdXBzIC0gcGVyaGFwcyBkdWUgdG8gc2V2ZXJhbCBmYWxsaW5nIGludG8gdGhlIHNhbWUgQ0hFTFNBIGdyaWQgY2VsbC4NCg0KRXhhbXBsZTogcGxvdHMgd2l0aGluIHNpdGUgMSwgYWx0aXR1ZGUgMjAsIHBsb3QgZ3JvdXAgMTogcGxvdCBQMTQ2IGlzIHNsaWdodGx5IG9mZiBhbmQgdGhlcmVmb3JlIGhhcyBkaWZmZXJlbnQgY2xpbWF0ZSB2YXJpYWJsZXMgdGhhbiB0aGUgb3RoZXIgb25lcw0KDQpgYGB7cn0NCmVudl9jb3ZfYmlvICU+JSBmaWx0ZXIodGF4b24gPT0gIkJldHVsYSBuYW5hIiAmIHNpdGVfYWx0X3Bsb3Rncm91cF9pZCA9PSAiMV8yMF8xIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBsb25nLCB5ID0gbGF0KSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwbG90KSwgaGp1c3QgPSAwLjAwMDEpICsgDQogIHhsaW0oYygtNTEuNzg2NzUsIC01MS43ODYzKSkNCmVudl9jb3ZfYmlvICU+JSBmaWx0ZXIodGF4b24gPT0gIkJldHVsYSBuYW5hIiAmIHNpdGVfYWx0X3Bsb3Rncm91cF9pZCA9PSAiMV8yMF8xIikgJT4lIA0KICBzZWxlY3Qoc2l0ZV9hbHRfcGxvdGdyb3VwX2lkLCBwbG90LCB0ZW1wamphX3RzXzMwKQ0KYGBgDQoNCkNoZWNrIGZvciBjb3JyZWxhdGlvbiBiZXR3ZWVuIHByZWRpY3RvcnM6DQoNCmBgYHtyfQ0KcHJlZGljdG9yc19zZXQgPC0gZW52X2Nvdl9iaW9fc3ViICU+JSANCiAgc2VsZWN0KGVuZHNfd2l0aCgiX3RzXzMwIiksICAgIyBDSEVMU0EgcHJlZGljdG9ycyBhdmVyYWdlZCBvdmVyIDEwLXllYXIgcGVyaW9kIHByaW9yIHRvIHN0dWR5IHllYXINCiAgICAgICAgIGluY2xpbl9kb3duLCBzcmksIHRyaSwgdHdpLCAgICAgICMgZW52aXJvbm1lbnRhbCBkYXRhDQogICAgICAgICBjb21wZXQpICU+JSANCiAgbmFtZXMoKQ0KIyBjcmVhdGUgYmFzaWMgY29ycmVsYXRpb24gbWF0cml4DQooY29yX21hdCA8LSBlbnZfY292X2Jpb19zdWIgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvcnNfc2V0KSAlPiUgDQogIGNvcnJlbGF0ZShkaWFnb25hbCA9IDEpICU+JSANCiAgIyBkcm9wIGFsbCB2YWx1ZXMgPCAuNCB0byBpbmNyZWFzZSByZWFkYWJpbGl0eQ0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgfiBpZmVsc2UoYWJzKC4pIDwgLjQsIE5BLCAuKSkpDQpgYGANCg0KJFxSaWdodGFycm93JCBNYXhpbXVtIHRlbXBlcmF0dXJlIGlzIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggSkpBIHRlbXBlcmF0dXJlLCBtaW5pbXVtIHRlbXBlcmF0dXJlIHdpdGggY29udGluZW50YWxpdHksIHNsb3BlIChpbmNsaW5fZG93bikgd2l0aCBzb2xhciByYWRpYXRpb24sIGFuZCBzcHJpbmcgcHJlY2lwaXRhdGlvbiB2YXJpYWJsZXMgd2l0aCBKSkEgcHJlY2lwaXRhdGlvbi4NCkxldCdzIGV4Y2x1ZGUgdGhlbSBzdGVwIGJ5IHN0ZXAgYW5kIGNoZWNrIHRoZSB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycyAoVklGKSBhbG9uZyB0aGUgd2F5LiBWSUYgdmFsdWVzID4gNSBpbmRpY2F0ZSBjb2xsaW5lYXJpdHkgaXNzdWVzLg0KDQpgYGB7cn0NCiMgZm9yIHRoZSB3aG9sZSBzZXQgb2YgcHJlZGljdG9ycw0KKHZpZl9wcmVkaWN0b3JzXzEgPC0gZW52X2Nvdl9iaW9fc3ViICU+JSANCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3JzX3NldCkgJT4lIA0KICB1c2RtOjp2aWYoKSkgIyU+JSBWaWV3KCkNCiMgPT4gZHJvcCB0ZW1wbWF4IChjb3JyZWxhdGVkIHcvIHRlbXBqamEpDQoodmlmX3ByZWRpY3RvcnNfMiA8LSBlbnZfY292X2Jpb19zdWIgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvcnNfc2V0LA0KICAgICAgICAgICAgICAgIC10ZW1wbWF4X3RzXzMwKSAlPiUgDQogIHVzZG06OnZpZigpKSAjJT4lIFZpZXcoKQ0KIyA9PiBkcm9wIHRlbXBtaW4gKGNvcnJlbGF0ZWQgdy8gdGVtcGNvbnQpDQoodmlmX3ByZWRpY3RvcnNfMyA8LSBlbnZfY292X2Jpb19zdWIgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvcnNfc2V0LA0KICAgICAgICAgICAgICAgIC10ZW1wbWF4X3RzXzMwLA0KICAgICAgICAgICAgICAgIC10ZW1wbWluX3RzXzMwKSAlPiUgDQogIHVzZG06OnZpZigpKSAjJT4lIFZpZXcoKQ0KIyA9PiBkcm9wIHByZWNpcGpmbWFtIChjb3JyZWxhdGVkIHcvIHByZWNpcGpqYSAmIHRlbXBjb250KQ0KKHZpZl9wcmVkaWN0b3JzXzQgPC0gZW52X2Nvdl9iaW9fc3ViICU+JSANCiAgZHBseXI6OnNlbGVjdChwcmVkaWN0b3JzX3NldCwNCiAgICAgICAgICAgICAgICAtdGVtcG1heF90c18zMCwNCiAgICAgICAgICAgICAgICAtdGVtcG1pbl90c18zMCwNCiAgICAgICAgICAgICAgICAtY29udGFpbnMoImpmbSIpKSAlPiUgDQogIHVzZG06OnZpZigpKSAjJT4lIFZpZXcoKQ0KIyA9PiBkcm9wIGluY2xpbl9kb3duIChjb3JyZWxhdGVkIHcvIFNSSSkNCih2aWZfcHJlZGljdG9yc181IDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgDQogIGRwbHlyOjpzZWxlY3QocHJlZGljdG9yc19zZXQsDQogICAgICAgICAgICAgICAgLXRlbXBtYXhfdHNfMzAsDQogICAgICAgICAgICAgICAgLXRlbXBtaW5fdHNfMzAsDQogICAgICAgICAgICAgICAgLWluY2xpbl9kb3duLA0KICAgICAgICAgICAgICAgIC1jb250YWlucygiamZtIikpICU+JSANCiAgdXNkbTo6dmlmKCkpICMlPiUgVmlldygpDQoodmlmX3ByZWRpY3RvcnNfNiA8LSBlbnZfY292X2Jpb19zdWIgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHByZWRpY3RvcnNfc2V0LA0KICAgICAgICAgICAgICAgIC10ZW1wbWF4X3RzXzMwLA0KICAgICAgICAgICAgICAgIC10ZW1wbWluX3RzXzMwLA0KICAgICAgICAgICAgICAgIC1pbmNsaW5fZG93biwNCiAgICAgICAgICAgICAgICAtY29udGFpbnMoIm1hbSIpKSAlPiUgDQogIHVzZG06OnZpZigpKSAjJT4lIFZpZXcoKQ0KYGBgDQoNCkFsbCBWSUYgYXJlIG5vdyA8IDMuMSAtPiBPSyEgV2UgY2FuIG5vdyBleGNsdWRlIHRoZSBkcm9wcGVkIHZhcmlhYmxlcyB0byBvYnRhaW4gdGhlIGZpbmFsIGRhdGFzZXQ6DQoNCmBgYHtyfQ0KZW52X2Nvdl9iaW9fc3ViIDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRlbXBtYXhfdHNfMzAsDQogICAgICAgICAgICAgICAgLXRlbXBtaW5fdHNfMzAsDQogICAgICAgICAgICAgICAgLWluY2xpbl9kb3duLA0KICAgICAgICAgICAgICAgIC1jb250YWlucygibWFtIikpDQpgYGANCg0KIyMjIGIpIHJhdyBkYXRhIHBsb3RzDQoNCiMjIyA+IHNwZWNpZXMgYWJ1bmRhbmNlIGFsb25nIHRoZSBncmFkaWVudA0KYGBge3J9DQoobnV1a19zcGVjX2FidW5kYW5jZV9wbG90IDwtIGdncGxvdChlbnZfY292X2JpbyAlPiUgDQogICAgICAgICANCiAgICAgICAgICMgbWFrZSBzaXRlIGEgZmFjdG9yDQogICAgICAgICBtdXRhdGUoc2l0ZSA9IGFzLmZhY3RvcihzaXRlKSkgJT4lIA0KICAgICAgICAgbXV0YXRlKHNpdGVfYWx0X2lkID0gZmFjdG9yKHNpdGVfYWx0X2lkLCBsZXZlbHMgPSBjKHBhc3RlKHJlcCgxLCAzKSwgYygiMjAiLCAiMTAwIiwgIjIwMCIpLCBzZXAgPSAiXyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKHJlcCgyLCAzKSwgYygiMjAiLCAiMTAwIiwgIjIwMCIpLCBzZXAgPSAiXyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKHJlcCgzLCA1KSwgYygiMjAiLCAiMTAwIiwgIjIwMCIsICIzMDAiLCAiNDAwIiksIHNlcCA9ICJfIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUocmVwKDQsIDYpLCBjKCIyMCIsICIxMDAiLCAiMjAwIiwgIjMwMCIsICI0MDAiLCAiNTAwIiksIHNlcCA9ICJfIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUocmVwKDUsIDYpLCBjKCIyMCIsICIxMDAiLCAiMjAwIiwgIjMwMCIsICI0MDAiLCAiNTAwIiksIHNlcCA9ICJfIikpKSkgJT4lIA0KICAgICAgICAgIyBncm91cCBieSBzaXRlIGFuZCBpc29jbGluZQ0KICAgICAgICAgZ3JvdXBfYnkoc2l0ZSwgc2l0ZV9hbHRfaWQpLCANCiAgICAgICANCiAgICAgICBhZXMoeCA9IHNpdGVfYWx0X2lkLCANCiAgICAgICAgICAgeSA9IGNvdmVyLCANCiAgICAgICAgICAgZmlsbCA9IHNpdGUpKSArIA0KICANCiAgIyBkcmF3IGJveHBsb3RzIG9mIGNvdmVyDQogIGdlb21fYm94cGxvdCgpICsgDQogIA0KICAjIHNwbGl0IGJ5IHRheG9uDQogIGZhY2V0X2dyaWQocm93cyA9IHZhcnModGF4b24pKSArDQogIA0KICAjIHNjYWxlX2ZpbGxfbWFudWFsKCkgKw0KICB0aGVtZV9idygpICsNCiAgeGxhYigic2l0ZSAvIGlzb2NsaW5lIikgKw0KICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEsIHNpemUgPSByZWwoMS4yKSksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpKSkpDQoNCiMgc2F2ZSBwbG90DQojIHNhdmVfcGxvdChmaWxlLnBhdGgoIi4uIiwgImZpZ3VyZXMiLCAibnV1a19zaHJ1Yl9kcml2ZXJzX3NwZWNpZXNfYWJ1bmRhbmNlX2dyYWRpZW50LmVwcyIpLA0KIyAgICAgICAgICAgbnV1a19zcGVjX2FidW5kYW5jZV9wbG90LCBiYXNlX2hlaWdodCA9IDE4LCBiYXNlX2FzcGVjdF9yYXRpbyA9IDAuOCkNCmBgYA0KDQojIyMgPiBwcmVkaWN0b3IgcGF0dGVybnMgYWxvbmcgdGhlIGdyYWRpZW50DQpgYGB7cn0NCiMgZGF0YSBjb21waWxhdGlvbiAtLS0tDQpwcmVkaWN0b3JzX3NldCA8LSBlbnZfY292X2JpbyAlPiUgDQogIHNlbGVjdChlbmRzX3dpdGgoIl90c18zMCIpLCAgICMgQ0hFTFNBIHByZWRpY3RvcnMgYXZlcmFnZWQgb3ZlciAxMC15ZWFyIHBlcmlvZCBwcmlvciB0byBzdHVkeSB5ZWFyDQogICAgICAgICBpbmNsaW5fZG93biwgc3JpLCB0cmksIHR3aSwgICAgICAjIGVudmlyb25tZW50YWwgZGF0YQ0KICAgICAgICAgY29tcGV0KSAlPiUgDQogIG5hbWVzKCkNCg0KcHJlZHNfcGxvdF9kYXRhIDwtIGVudl9jb3ZfYmlvICU+JSANCiAgICAgICAgIA0KICAgICAgICAgIyBjb252ZXJ0IHNpdGUsIGlzb2NsaW5lICYgcGxvdGdyb3VwIHRvIGZhY3RvcnMNCiAgICAgICAgIG11dGF0ZShzaXRlID0gYXMuZmFjdG9yKHNpdGUpKSAlPiUgDQogICAgICAgICBtdXRhdGUoc2l0ZV9hbHRfaWQgPSBmYWN0b3Ioc2l0ZV9hbHRfaWQsIGxldmVscyA9IGMocGFzdGUocmVwKDEsIDMpLCBjKCIyMCIsICIxMDAiLCAiMjAwIiksIHNlcCA9ICJfIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUocmVwKDIsIDMpLCBjKCIyMCIsICIxMDAiLCAiMjAwIiksIHNlcCA9ICJfIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUocmVwKDMsIDUpLCBjKCIyMCIsICIxMDAiLCAiMjAwIiwgIjMwMCIsICI0MDAiKSwgc2VwID0gIl8iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShyZXAoNCwgNiksIGMoIjIwIiwgIjEwMCIsICIyMDAiLCAiMzAwIiwgIjQwMCIsICI1MDAiKSwgc2VwID0gIl8iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShyZXAoNSwgNiksIGMoIjIwIiwgIjEwMCIsICIyMDAiLCAiMzAwIiwgIjQwMCIsICI1MDAiKSwgc2VwID0gIl8iKSkpKSAlPiUgDQogICAgICAgICBtdXRhdGUocGxvdGdyb3VwID0gYXMuZmFjdG9yKHBsb3Rncm91cCkpICU+JSANCiAgICAgICAgICAgDQogICAgICAgICBzZWxlY3Qoc2l0ZSwgc2l0ZV9hbHRfaWQsIHByZWRpY3RvcnNfc2V0KSAlPiUgDQogICAgICAgICANCiAgICAgICAgICMgcGl2b3QgdG8gbG9uZyBmb3JtYXQNCiAgICAgICAgIHBpdm90X2xvbmdlcihjb2xzID0gcHJlZGljdG9yc19zZXQsDQogICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAicHJlZGljdG9yIiwNCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUgDQogICAgICAgICAgIA0KICAgICAgICAgIyBjb252ZXJ0IHByZWRpY3RvciBjb2wgdG8gZmFjdG9yDQogICAgICAgICBtdXRhdGUocHJlZGljdG9yID0gYXMuZmFjdG9yKHByZWRpY3RvcikpICU+JSANCiAgICAgICAgDQogICAgICAgICAjIHJlbmFtZSBwcmVkaWN0b3JzDQogICAgICAgICBtdXRhdGUocHJlZGljdG9yID0gZmN0X3JlY29kZShwcmVkaWN0b3IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3VtbWVyIFxuIHRlbXBlcmF0dXJlIFvCsENdIiA9ICJ0ZW1wamphX3RzXzMwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ5ZWFybHkgbWF4aW11bSBcbiB0ZW1wZXJhdHVyZSBbwrBDXSIgPSAidGVtcG1heF90c18zMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAieWVhcmx5IG1pbmltdW0gXG4gdGVtcGVyYXR1cmUgW8KwQ10iID0gInRlbXBtaW5fdHNfMzAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImFubnVhbCB0ZW1wZXJhdHVyZSBcbiB2YXJpYWJpbGl0eSBbwrBDXSIgPSAidGVtcGNvbnRfdHNfMzAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImN1bXVsYXRpdmUgc3VtbWVyIFxuIHByZWNpcGl0YXRpb24gW21tXSIgPSAicHJlY2lwamphX3RzXzMwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdW11bGF0aXZlIHdpbnRlci1zcHJpbmcgXG4gcHJlY2lwaXRhdGlvbiBbbW1dIiA9ICJwcmVjaXBqZm1hbV90c18zMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY3VtdWxhdGl2ZSBzcHJpbmcgXG4gcHJlY2lwaXRhdGlvbiBbbW1dIiA9ICJwcmVjaXBtYW1fdHNfMzAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNsb3BlIGFuZ2xlIFvCsF0iID0gImluY2xpbl9kb3duIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTb2xhciBSYWRpYXRpb24gXG4gSW5kZXgiID0gInNyaSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGVycmFpbiBSdWdnZWRuZXNzIFxuIEluZGV4IiA9ICJ0cmkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvcG9ncmFwaGljIFdldG5lc3MgXG4gSW5kZXgiID0gInR3aSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAib3Zlcmdyb3dpbmcgXG4gY29tcGV0aXRpb24iID0gImNvbXBldCIpLA0KICAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGZjdF9yZWxldmVsKHByZWRpY3RvciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3VtbWVyIFxuIHRlbXBlcmF0dXJlIFvCsENdIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAieWVhcmx5IG1heGltdW0gXG4gdGVtcGVyYXR1cmUgW8KwQ10iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ5ZWFybHkgbWluaW11bSBcbiB0ZW1wZXJhdHVyZSBbwrBDXSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImFubnVhbCB0ZW1wZXJhdHVyZSBcbiB2YXJpYWJpbGl0eSBbwrBDXSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImN1bXVsYXRpdmUgc3VtbWVyIFxuIHByZWNpcGl0YXRpb24gW21tXSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImN1bXVsYXRpdmUgd2ludGVyLXNwcmluZyBcbiBwcmVjaXBpdGF0aW9uIFttbV0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdW11bGF0aXZlIHNwcmluZyBcbiBwcmVjaXBpdGF0aW9uIFttbV0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzbG9wZSBhbmdsZSBbwrBdIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU29sYXIgUmFkaWF0aW9uIFxuIEluZGV4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGVycmFpbiBSdWdnZWRuZXNzIFxuIEluZGV4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG9wb2dyYXBoaWMgV2V0bmVzcyBcbiBJbmRleCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm92ZXJncm93aW5nIFxuIGNvbXBldGl0aW9uIikpICU+JSANCiAgICAgICAgICAgDQogICAgICAgICAjIGdyb3VwIGJ5IHNpdGUgJiBpc29jbGluZSANCiAgICAgICAgIGdyb3VwX2J5KHNpdGUsIHNpdGVfYWx0X2lkKQ0KDQojIGNsaW1hdGljIHByZWRpY3RvcnMgLS0tLQ0KcHJlZGljdG9yc19zZXRfY2xpbV9sb25nIDwtIGMoInN1bW1lciBcbiB0ZW1wZXJhdHVyZSBbwrBDXSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAieWVhcmx5IG1heGltdW0gXG4gdGVtcGVyYXR1cmUgW8KwQ10iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgInllYXJseSBtaW5pbXVtIFxuIHRlbXBlcmF0dXJlIFvCsENdIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbm51YWwgdGVtcGVyYXR1cmUgXG4gdmFyaWFiaWxpdHkgW8KwQ10iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgImN1bXVsYXRpdmUgc3VtbWVyIFxuIHByZWNpcGl0YXRpb24gW21tXSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiY3VtdWxhdGl2ZSB3aW50ZXItc3ByaW5nIFxuIHByZWNpcGl0YXRpb24gW21tXSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiY3VtdWxhdGl2ZSBzcHJpbmcgXG4gcHJlY2lwaXRhdGlvbiBbbW1dIikNCg0KKG51dWtfcHJlZHNfY2xpbV9ncmFkaWVudF9wbG90IDwtIGdncGxvdChwcmVkc19wbG90X2RhdGEgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwcmVkaWN0b3IgJWluJSBwcmVkaWN0b3JzX3NldF9jbGltX2xvbmcpLA0KICAgICAgIA0KICAgICAgIGFlcyh4ID0gc2l0ZV9hbHRfaWQsIA0KICAgICAgICAgICB5ID0gdmFsdWUsIA0KICAgICAgICAgICBmaWxsID0gc2l0ZSkpICsgDQogIA0KICAjIGRyYXcgYm94cGxvdHMgb2YgdmFsdWVzDQogIGdlb21fYm94cGxvdCgpICsgDQogIA0KICAjIHNwbGl0IGJ5IHRheG9uDQogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMocHJlZGljdG9yKSwgc2NhbGVzID0gImZyZWVfeSIpICsNCg0KICAjIHNjYWxlX2ZpbGxfbWFudWFsKCkgKw0KICB0aGVtZV9idygpICsNCiAgeGxhYigic2l0ZSAvIGlzb2NsaW5lIikgKw0KICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEsIHNpemUgPSByZWwoMS4yKSksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpKSkpDQoNCiMgc2F2ZSBwbG90DQojIHNhdmVfcGxvdChmaWxlLnBhdGgoIi4uIiwgImZpZ3VyZXMiLCAibnV1a19zaHJ1Yl9kcml2ZXJzX3ByZWRzX2NsaW1fZ3JhZGllbnQuZXBzIiksDQojICAgICAgICAgICBudXVrX3ByZWRzX2NsaW1fZ3JhZGllbnRfcGxvdCwgYmFzZV9oZWlnaHQgPSAxNSwgYmFzZV9hc3BlY3RfcmF0aW8gPSAwLjgpDQoNCiMgZW52aXJvbm1lbnRhbCBwcmVkaWN0b3JzIC0tLS0NCnByZWRpY3RvcnNfc2V0X2Vudl9sb25nIDwtIGMoInNsb3BlIGFuZ2xlIFvCsF0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNvbGFyIFJhZGlhdGlvbiBcbiBJbmRleCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiVGVycmFpbiBSdWdnZWRuZXNzIFxuIEluZGV4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3BvZ3JhcGhpYyBXZXRuZXNzIFxuIEluZGV4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJvdmVyZ3Jvd2luZyBcbiBjb21wZXRpdGlvbiIpDQoNCihudXVrX3ByZWRzX2Vudl9ncmFkaWVudF9wbG90IDwtIGdncGxvdChwcmVkc19wbG90X2RhdGEgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwcmVkaWN0b3IgJWluJSBwcmVkaWN0b3JzX3NldF9lbnZfbG9uZyksDQogICAgICAgDQogICAgICAgYWVzKHggPSBzaXRlX2FsdF9pZCwgDQogICAgICAgICAgIHkgPSB2YWx1ZSwgDQogICAgICAgICAgIGZpbGwgPSBzaXRlKSkgKyANCiAgDQogICMgZHJhdyBib3hwbG90cyBvZiB2YWx1ZXMNCiAgZ2VvbV9ib3hwbG90KCkgKyANCiAgDQogICMgc3BsaXQgYnkgdGF4b24NCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhwcmVkaWN0b3IpLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KDQogICMgc2NhbGVfZmlsbF9tYW51YWwoKSArDQogIHRoZW1lX2J3KCkgKw0KICB4bGFiKCJzaXRlIC8gaXNvY2xpbmUiKSArDQogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSwgc2l6ZSA9IHJlbCgxLjIpKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMikpKSkNCg0KIyBzYXZlIHBsb3QNCiMgc2F2ZV9wbG90KGZpbGUucGF0aCgiLi4iLCAiZmlndXJlcyIsICJudXVrX3NocnViX2RyaXZlcnNfcHJlZHNfZW52X2dyYWRpZW50LmVwcyIpLA0KIyAgICAgICAgICAgbnV1a19wcmVkc19lbnZfZ3JhZGllbnRfcGxvdCwgYmFzZV9oZWlnaHQgPSAxNSwgYmFzZV9hc3BlY3RfcmF0aW8gPSAwLjgpDQoNCiMgZmluYWwgc2V0IG9mIHByZWRpY3RvcnMgLS0tLQ0KcHJlZGljdG9yc19zZXRfZmluYWxfbG9uZyA8LSBjKCJzdW1tZXIgXG4gdGVtcGVyYXR1cmUgW8KwQ10iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbm51YWwgdGVtcGVyYXR1cmUgXG4gdmFyaWFiaWxpdHkgW8KwQ10iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdW11bGF0aXZlIHN1bW1lciBcbiBwcmVjaXBpdGF0aW9uIFttbV0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTb2xhciBSYWRpYXRpb24gXG4gSW5kZXgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUZXJyYWluIFJ1Z2dlZG5lc3MgXG4gSW5kZXgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3BvZ3JhcGhpYyBXZXRuZXNzIFxuIEluZGV4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAib3Zlcmdyb3dpbmcgXG4gY29tcGV0aXRpb24iKQ0KDQoobnV1a19wcmVkc19maW5hbF9ncmFkaWVudF9wbG90IDwtIGdncGxvdChwcmVkc19wbG90X2RhdGEgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwcmVkaWN0b3IgJWluJSBwcmVkaWN0b3JzX3NldF9maW5hbF9sb25nKSwNCiAgICAgICANCiAgICAgICBhZXMoeCA9IHNpdGVfYWx0X2lkLCANCiAgICAgICAgICAgeSA9IHZhbHVlLCANCiAgICAgICAgICAgZmlsbCA9IHNpdGUpKSArIA0KICANCiAgIyBkcmF3IGJveHBsb3RzIG9mIHZhbHVlcw0KICBnZW9tX2JveHBsb3QoKSArIA0KICANCiAgIyBzcGxpdCBieSB0YXhvbg0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKHByZWRpY3RvciksIHNjYWxlcyA9ICJmcmVlX3kiKSArDQoNCiAgIyBzY2FsZV9maWxsX21hbnVhbCgpICsNCiAgdGhlbWVfYncoKSArDQogIHhsYWIoInNpdGUgLyBpc29jbGluZSIpICsNCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxLCBzaXplID0gcmVsKDEuMikpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yKSkpKQ0KDQojIHNhdmUgcGxvdA0KIyBzYXZlX3Bsb3QoZmlsZS5wYXRoKCIuLiIsICJmaWd1cmVzIiwgIm51dWtfc2hydWJfZHJpdmVyc19wcmVkc19maW5hbF9ncmFkaWVudC5lcHMiKSwNCiMgICAgICAgICAgIG51dWtfcHJlZHNfZmluYWxfZ3JhZGllbnRfcGxvdCwgYmFzZV9oZWlnaHQgPSAxNSwgYmFzZV9hc3BlY3RfcmF0aW8gPSAwLjgpDQpgYGANCg0KPGJyPg0KDQojIyMgPiBjb3ZlciB2cy4gcHJlZGljdG9ycyBwZXIgc3BlY2llcw0KDQpIb3cgZG8gdGhlIHRyZW5kcyBpbiBjb3ZlciByZXNwb25zZSBsb29rIGZvciBlYWNoIG9mIHRoZSBwcmVkaWN0b3JzPyBQbG90IHBhbmVscyBiZWxvdyBzaG93IGxpbmVhciAoZ3JlZW4pIGFuZCBxdWFkcmF0aWMgKG9yYW5nZSkgdHJlbmRsaW5lcyBkZXJpdmVkIGZyb20gbGluZWFyIG1vZGVscyAoZGlmZmVyZW50IHRoYW4gdGhlIEJheWVzaWFuIGFwcHJvYWNoIHVzZWQgZm9yIGFuYWx5c2lzISBidXQgYW55d2F5IHVzZWZ1bCB0byBjYXRjaCB0cmVuZHMpOg0KYGBge3J9DQojIFByZXBhcmUgZGF0YSBmb3IgcGFuZWwgcGxvdHMgZm9yIGNvdmVyIGFnYWluc3QgcHJlZGljdG9ycyBmb3IgZWFjaCBzcGVjaWVzDQplbnZfY292X2Jpby5sb25nIDwtIGVudl9jb3ZfYmlvICU+JSANCiAgc2VsZWN0KHRheG9uLA0KICAgICAgICAgdGVtcGpqYV90c18zMCwNCiAgICAgICAgIHRlbXBjb250X3RzXzMwLA0KICAgICAgICAgcHJlY2lwamphX3RzXzMwLA0KICAgICAgICAgc3JpLA0KICAgICAgICAgdHJpLA0KICAgICAgICAgdHdpLA0KICAgICAgICAgY29tcGV0LA0KICAgICAgICAgY292ZXIpICU+JSANCiAgIyBwaXZvdCB0byBsb25nIGZvcm1hdA0KICBwaXZvdF9sb25nZXIoY29scyA9IGModGVtcGpqYV90c18zMCwNCiAgICAgICAgICAgICAgICAgICAgICAgIHRlbXBjb250X3RzXzMwLA0KICAgICAgICAgICAgICAgICAgICAgICAgcHJlY2lwamphX3RzXzMwLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3JpLA0KICAgICAgICAgICAgICAgICAgICAgICAgdHJpLA0KICAgICAgICAgICAgICAgICAgICAgICAgdHdpLA0KICAgICAgICAgICAgICAgICAgICAgICAgY29tcGV0KSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInByZWRpY3RvciIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicHJlZF92YWx1ZSIpDQoNCiMgcnVuDQpwcmVkLnBsb3QuZ3JpZChlbnZfY292X2Jpby5sb25nKQ0KYGBgDQoNCg0KIyMjIGMpIGFkanVzdGlvbiBvZiBkYXRhIHN0cnVjdHVyZQ0KDQpEYXRhIHdhcyBvcmRlcmVkIGJ5IHNpdGUvYWx0aXR1ZGUvcGxvdGdyb3VwIGFuZCB0YXhvbg0KYGBge3J9DQplbnZfY292X2Jpb19zdWIgPC0gZW52X2Nvdl9iaW9fc3ViW29yZGVyKGVudl9jb3ZfYmlvX3N1YiRzaXRlX2FsdF9wbG90Z3JvdXBfaWQsIGVudl9jb3ZfYmlvX3N1YiR0YXhvbiksXQ0KDQpgYGANCg0KQXMgSkFHUyBpcyBvbmx5IGFibGUgdG8gaGFuZGxlIG51bWVyaWMgaW5wdXQsIGFsbCB2YXJpYWJsZXMgYXJlIGFzc2lnbmVkIGEgbnVtZXJpYyBpZGVudGlmaWVyOg0KYGBge3J9DQplbnZfY292X2Jpb19zdWIkcGxvdGdyb3VwLk5VTSA8LSBhcy5udW1lcmljKGZhY3RvcihlbnZfY292X2Jpb19zdWIkc2l0ZV9hbHRfcGxvdGdyb3VwX2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGVudl9jb3ZfYmlvX3N1YiRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSkNCmVudl9jb3ZfYmlvX3N1YiRwbG90Lk5VTSA8LSBhcy5udW1lcmljKGZhY3RvcihlbnZfY292X2Jpb19zdWIkcGxvdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUoZW52X2Nvdl9iaW9fc3ViJHBsb3QpKSkNCmVudl9jb3ZfYmlvX3N1YiRzaXRlX2FsdC5OVU0gPC0gYXMubnVtZXJpYyhmYWN0b3IoZW52X2Nvdl9iaW9fc3ViJHNpdGVfYWx0X2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZShlbnZfY292X2Jpb19zdWIkc2l0ZV9hbHRfaWQpKSkNCmVudl9jb3ZfYmlvX3N1YiRzaXRlLk5VTSA8LSBhcy5udW1lcmljKGZhY3RvcihlbnZfY292X2Jpb19zdWIkc2l0ZSwgbGV2ZWxzID0gdW5pcXVlKGVudl9jb3ZfYmlvX3N1YiRzaXRlKSkpDQplbnZfY292X2Jpb19zdWIkdGF4b24uTlVNIDwtIGFzLm51bWVyaWMoZmFjdG9yKGVudl9jb3ZfYmlvX3N1YiR0YXhvbiwgbGV2ZWxzID0gdW5pcXVlKGVudl9jb3ZfYmlvX3N1YiR0YXhvbikpKQ0KYGBgDQoNClRheGEgd2VyZSBjb2RlZCBhcyBmb2xsb3dzOiANCmBgYHtyfQ0KZGF0YS5mcmFtZSh0YXhvbiA9IGxldmVscyhlbnZfY292X2Jpb19zdWIkdGF4b24pLA0KICAgICAgICAgICBudW0gPSB1bmlxdWUoZW52X2Nvdl9iaW9fc3ViJHRheG9uLk5VTSkpDQpgYGANCg0KTnVtZXJpYyBwcmVkaWN0b3JzIHdlcmUgc2NhbGVkIGFuZCBjZW50ZXJlZDogDQpgYGB7cn0NCm51bV9wcmVkIDwtIGVudl9jb3ZfYmlvX3N1YiAlPiUgc2VsZWN0KGFsdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZHNfd2l0aCgiX3RzXzMwIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3JpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyaSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJ0d2kiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaGVzKCJjb21wZXQiKSkNCmZvcihpIGluIDE6bGVuZ3RoKG51bV9wcmVkKSl7DQogIGNvbCA8LSBjb2xuYW1lcyhudW1fcHJlZFtpXSkNCiAgZW52X2Nvdl9iaW9fc3ViW3Bhc3RlMChjb2wsIkMiKV0gPC0gYXMubnVtZXJpYyhzY2FsZShudW1fcHJlZFtpXSwgc2NhbGUgPSBUUlVFLCBjZW50ZXIgPSBUUlVFKSkNCn0NCmBgYA0KDQpUbyBhY2NvdW50IGZvciB0aGUgcmFuZ2Ugb2YgdGhlIGNvdmVyIHJlc3BvbnNlICgkMCBcbGVxIGNvdmVyIFxsZXEgMSQpLCB0aGUgbW9kZWwgbmVlZHMgYSBtaXhlZCBzdHJ1Y3R1cmUgaW5jb3Jwb3JhdGluZyBhIGJldGEgZGlzdHJpYnV0aW9uIChmb3IgYWxsIGNvbnRpbnVvdXMgdmFsdWVzIHdpdGggJDAgPCBjb3ZlciA8IDEkKSBhbmQgYSBiaW5vbWlhbCBkaXN0cmlidXRpb24gKGZvciBhbGwgZGlzY3JldGUgdmFsdWVzIG9mICRjb3ZlciA9IFx7MCwgMVx9JCkuIEFuIGFkZGl0aW9uYWwgdmFyaWFibGUgKmNvdmVyX2Rpc2NyZXRlKiB3YXMgaW50cm9kdWNlZCB0byBzZXBhcmF0ZSB0aGUgZGF0YXNldCBpbnRvIGRpc2NyZXRlICg9IDEpIGFuZCBjb250aW51b3VzICg9IDApIGNvdmVyIHZhbHVlczoNCmBgYHtyfQ0KZW52X2Nvdl9iaW9fc3ViJGNvdmVyX2Rpc2NyZXRlIDwtIGlmZWxzZShlbnZfY292X2Jpb19zdWIkY292ZXIgPT0gMSB8IGVudl9jb3ZfYmlvX3N1YiRjb3ZlciA9PSAwLCAxLCAwKQ0KYGBgDQoNCiMjIyBUcmlhbDogKkJldHVsYSBuYW5hKg0KVGhlIGRhdGFzZXQgd2FzIHRoZW4gcmVhZHkgdG8gYmUgc3BsaXQgdXAgaW50byB0aGUgc3BlY2llcyBvZiBpbnRlcmVzdC4gQXMgYSBmaXJzdCB0cmlhbCwgSSBmb2N1c2VkIG9uICpCZXR1bGEgbmFuYSo6DQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQojIGNvbXBsZXRlIEJldHVsYSBuYW5hIGRhdGENCkJldE5hbi50b3QgPC0gZmlsdGVyKGVudl9jb3ZfYmlvX3N1YiwgdGF4b24gPT0gIkJldHVsYSBuYW5hIikNCiMgZGlzY3JldGUgY292ZXIgdmFsdWVzDQpCZXROYW4uZGlzIDwtIGZpbHRlcihCZXROYW4udG90LCBjb3Zlcl9kaXNjcmV0ZSA9PSAxKSAjIGNvbnRhaW5zIG9ubHkgemVyb3MgYXMgcmVzcG9uc2VzDQojIGNvbnRpbnVvdXMgY292ZXIgdmFsdWVzDQpCZXROYW4uY29udCA8LSBmaWx0ZXIoQmV0TmFuLnRvdCwgY292ZXJfZGlzY3JldGUgPT0gMCkNCmBgYA0KDQojIyMgPiBhc3NlbWJsaW5nIGRhdGEgZm9yIG1vZGVsIGlucHV0IGluIGEgbGlzdA0KDQpKQUdTIG5lZWRzIGRhdGEgaW5wdXQgaW4gbGlzdCBmb3JtYXQsIHNvIEkgcHJvdmlkZWQgYWxsIHJlbGV2YW50IHZhcmlhYmxlcyBhcyBmb2xsb3dzOg0KYGBge3IsIGV2YWwgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQ0KIyBDb21waWxlIGRhdGEgaW50byBsaXN0ICMjIyMNCnNocnViX2dyYWRpZW50X2phZ3MuQmV0TmFuLmRhdGEgPC0gbGlzdCgNCiAgDQogICMgcGxvdCBsZXZlbCBwcmVkaWN0b3JzLCBmb3IgZGlzY3JldGUuLi4NCiAgY292LmRpcyA9IEJldE5hbi5kaXMkY292ZXIsDQogIHBsb3Rncm91cC5kaXMgPSBCZXROYW4uZGlzJHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuZGlzID0gQmV0TmFuLmRpcyRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uZGlzID0gQmV0TmFuLmRpcyRpbmNsaW5fZG93bkMsDQogIHNyaS5kaXMgPSBCZXROYW4uZGlzJHNyaUMsDQogIHRyaS5kaXMgPSBCZXROYW4uZGlzJHRyaUMsDQogIHR3aS5kaXMgPSBCZXROYW4uZGlzJHR3aUMsDQogIGNvbXBldC5kaXMgPSBCZXROYW4uZGlzJGNvbXBldEMsDQogIE5fZGlzY3JldGUgPSBucm93KEJldE5hbi5kaXMpLA0KICANCiAgIyAuLi5hbmQgY29udGludW91cyBwYXJ0IG9mIHRoZSBkYXRhDQogIGNvdi5jb250ID0gQmV0TmFuLmNvbnQkY292ZXIsDQogIHBsb3Rncm91cC5jb250ID0gQmV0TmFuLmNvbnQkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5jb250ID0gQmV0TmFuLmNvbnQkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmNvbnQgPSBCZXROYW4uY29udCRpbmNsaW5fZG93bkMsDQogIHNyaS5jb250ID0gQmV0TmFuLmNvbnQkc3JpQywNCiAgdHJpLmNvbnQgPSBCZXROYW4uY29udCR0cmlDLA0KICB0d2kuY29udCA9IEJldE5hbi5jb250JHR3aUMsDQogIGNvbXBldC5jb250ID0gQmV0TmFuLmNvbnQkY29tcGV0QywNCiAgTl9jb250ID0gbnJvdyhCZXROYW4uY29udCksDQogIA0KICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycw0KICB0ZW1wamphLnRvdCA9IEJldE5hbi50b3QkdGVtcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoQmV0TmFuLnRvdCRwbG90Z3JvdXAuTlVNKV0sICMgb25lIHZhbHVlIHBlciB0WHBnDQogICMgdGVtcG1heC50b3QgPSBCZXROYW4udG90JHRlbXBtYXhfdHNfMzBDWyFkdXBsaWNhdGVkKEJldE5hbi50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHRlbXBtaW4udG90ID0gQmV0TmFuLnRvdCR0ZW1wbWluX3RzXzMwQ1shZHVwbGljYXRlZChCZXROYW4udG90JHBsb3Rncm91cC5OVU0pXSwNCiAgdGVtcGNvbnQudG90ID0gQmV0TmFuLnRvdCR0ZW1wY29udF90c18zMENbIWR1cGxpY2F0ZWQoQmV0TmFuLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHByZWNpcGpqYS50b3QgPSBCZXROYW4udG90JHByZWNpcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoQmV0TmFuLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgcHJlY2lwamZtYW0udG90ID0gQmV0TmFuLnRvdCRwcmVjaXBqZm1hbV90c18zMENbIWR1cGxpY2F0ZWQoQmV0TmFuLnRvdCRwbG90Z3JvdXAuTlVNKV0NCiAgTl9wbG90Z3JvdXBzID0gbGVuZ3RoKHVuaXF1ZShCZXROYW4udG90JHNpdGVfYWx0X3Bsb3Rncm91cF9pZCkpDQogIA0KICAjICMgc2l0ZS9hbHQgbGV2ZWwgcHJlZGljdG9ycw0KICAjIGFsdC50b3QgPSBCZXROYW4udG90JGFsdENbIWR1cGxpY2F0ZWQoQmV0TmFuLnRvdCRzaXRlX2FsdC5OVU0pXSwNCiAgIyBOX2lzb2NsaW5lcyA9IGxlbmd0aCh1bmlxdWUoQmV0TmFuLnRvdCRzaXRlX2FsdF9pZCkpDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5CZXROYW4uZGF0YSkNCmBgYA0KDQojIyMgPiBzcGVjaWZ5aW5nIG1vZGVsDQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQp3cml0ZSgiDQogIA0KICBtb2RlbHsNCiAgICANCiAgICAjIHByaW9ycw0KICAgICAgDQogICAgICBpbnRlcmNlcHQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICANCiAgICAgIGIuY29tcGV0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zcmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICAjIGIuaW5jbGluX2Rvd24gfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudHdpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KDQogICAgICBzaWdtYS5wbG90Z3JvdXAgfiBkdW5pZigwLDEwMCkNCiAgICAgIHRhdS5wbG90Z3JvdXAgPC0gMS8oc2lnbWEucGxvdGdyb3VwICogc2lnbWEucGxvdGdyb3VwKQ0KICAgICAgDQogICAgICAjIHNpZ21hLmlzb2NsaW5lIH4gZHVuaWYoMCwxMDApDQogICAgICAjIHRhdS5pc29jbGluZSA8LSAxLyhzaWdtYS5pc29jbGluZSAqIHNpZ21hLmlzb2NsaW5lKQ0KICAgICAgIyANCiAgICAgICMgYi5hbHQueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLmFsdC54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBtYXgueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBtYXgueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wbWluLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wbWluLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBjb250LnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIucHJlY2lwamZtYW0ueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnByZWNpcGpmbWFtLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIHBoaSB+IGRnYW1tYSgwLjEsIDAuMSkNCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBkaXNjcmV0ZSBwYXJ0DQoNCiAgICAgIGZvciAoaSBpbiAxOk5fZGlzY3JldGUpeyANCiAgICAgICAgY292LmRpc1tpXSB+IGRiZXJuKG11W2ldKQ0KICAgICAgICBsb2dpdChtdVtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmRpc1tpXV0gKyAjQUIgYWRkZWQgdGhpcywgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICAjIGJfaXNvY2xpbmVbaXNvY2xpbmUuZGlzW2ldXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi5pbmNsaW5fZG93biAqIGluY2xpbl9kb3duLmRpc1tpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnR3aSAqIHR3aS5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLmRpc1tpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5kaXNbaV0NCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBjb250aW51b3VzIHBhcnQNCg0KICAgICAgZm9yIChqIGluIDE6Tl9jb250KXsNCiAgICAgICAgY292LmNvbnRbal0gfiBkYmV0YShwW2pdLCBxW2pdKQ0KICAgICAgICBwW2pdIDwtIG11MltqXSAqIHBoaQ0KICAgICAgICBxW2pdIDwtICgxIC0gbXUyW2pdKSAqIHBoaQ0KICAgICAgICBsb2dpdChtdTJbal0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5jb250W2pdXSArICNBQiBhZGRlZCB0aGlzLCB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgICMgYl9pc29jbGluZVtpc29jbGluZS5jb250W2pdXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi5pbmNsaW5fZG93biAqIGluY2xpbl9kb3duLmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcG1heC54ICogdGVtcG1heC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBtYXgueDIgKiAodGVtcG1heC50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcG1pbi54ICogdGVtcG1pbi50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBtaW4ueDIgKiAodGVtcG1pbi50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54MiAqICh0ZW1wY29udC50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54ICogcHJlY2lwamphLnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpICMgKw0KICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamZtYW0ueCAqIHByZWNpcGpmbWFtLnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamZtYW0ueDIgKiAocHJlY2lwamZtYW0udG90W2tdXjIpDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgIyBmb3IgKGwgaW4gMTpOX2lzb2NsaW5lcyl7ICNsZW5ndGggb2YgdG90YWwgaXNvY2xpbmVzDQogICAgICAjICAgYl9pc29jbGluZVtsXSB+IGRub3JtKG11Lmlzb2NsaW5lW2xdLHRhdS5pc29jbGluZSkNCiAgICAgICMgICBtdS5pc29jbGluZVtsXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICMgICANCiAgICAgICMgICAgICAgICAgICAgICAjIGlzb2NsaW5lLWxldmVsIHByZWRpY3Rvcg0KICAgICAgIyAgICAgICAgICAgICAgIGIuYWx0LnggKiBhbHQudG90W2xdDQogICAgICAjIH0NCg0KICAgIA0KICAgICAgfQ0KICAiLCBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5CZXROYW4uamFncyIpKQ0KYGBgDQoNCi4uLmFuZCB0aGUgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQ6DQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQpwYXJhbXMgPC0gYygiaW50ZXJjZXB0IiwNCiAgICAgICAgICAgICMgImIuYWx0LngiLA0KICAgICAgICAgICAgImIudGVtcGpqYS54IiwgImIudGVtcGpqYS54MiIsDQogICAgICAgICAgICAjICJiLnRlbXBtYXgueCIsICJiLnRlbXBtYXgueDIiLA0KICAgICAgICAgICAgIyAiYi50ZW1wbWluLngiLCAiYi50ZW1wbWluLngyIiwNCiAgICAgICAgICAgICJiLnRlbXBjb250LngiLCAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAiYi5wcmVjaXBqamEueCIsICJiLnByZWNpcGpqYS54MiIsDQogICAgICAgICAgICAjICJiLnByZWNpcGpmbWFtLngiLCAiYi5wcmVjaXBqZm1hbS54MiIsDQogICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICMgImIuaW5jbGluX2Rvd24iLCANCiAgICAgICAgICAgICJiLnNyaSIsDQogICAgICAgICAgICAiYi50cmkiLA0KICAgICAgICAgICAgImIudHdpIiwNCiAgICAgICAgICAgICJiX3Bsb3Rncm91cFsxXSIsImJfcGxvdGdyb3VwWzJdIiwiYl9wbG90Z3JvdXBbM10iLCJiX3Bsb3Rncm91cFs2M10iLA0KICAgICAgICAgICAgImJfaXNvY2xpbmVbMV0iLCJiX2lzb2NsaW5lWzJdIiwiYl9pc29jbGluZVsyMV0iLA0KICAgICAgICAgICAgInNpZ21hLnBsb3Rncm91cCIsInBoaSIpDQpgYGANCg0KIyMjID4gcnVuICYgZXZhbHVhdGUgbW9kZWwNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCiMgcnVuIG1vZGVsDQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5CZXROYW4uZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5CZXROYW4uamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gODAwMCwgbi5idXJuaW4gPSA2MDAwLCAgICAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikgDQoNCnBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbikgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KTm90ZXMgYXQgZmlyc3QgZ2xhbmNlOg0KDQoqIHF1YWRyYXRpYyBmaXQgYmV0dGVyIGZvciB0ZW1wZXJhdHVyZSB2YXJpYWJsZXMsIGxpbmVhciBmaXQgYmV0dGVyIGZvciBwcmVjaXBpdGF0aW9uIHZhcmlhYmxlcw0KKiB0YmMNCg0KQXMgdGhlIG1vZGVsIGNvbnZlcmdlcyB3ZWxsLCB3ZSBjYW4gcHJvY2VlZCB0byBhcHBseSBpdCB0byBhbGwgb2YgdGhlIHNwZWNpZXMuDQoNCjxicj4NCg0KIyMjIEFsbCBzcGVjaWVzDQpUaGUgZGF0YXNldCB3YXMgdGhlbiByZWFkeSB0byBiZSBzcGxpdCB1cCBpbnRvIHRoZSBzcGVjaWVzIG9mIGludGVyZXN0LiBXZSBjcmVhdGUgc2VwYXJhdGUgZGF0YSBzdWJzZXRzIGZvciBhbGwvZGlzY3JldGUvY29udGludW91cyByZXNwb25zZSB2YXJpYWJsZSB2YWx1ZXMgZm9yIGVhY2ggc3BlY2llczoNCmBgYHtyfQ0KIyBzcGxpdCBkYXRhZnJhbWUgYnkgdGF4b24NCmVudl9jb3ZfYmlvX3N1Yl9zcGVjLnRvdCA8LSBzcGxpdChlbnZfY292X2Jpb19zdWIsIGVudl9jb3ZfYmlvX3N1YiR0YXhvbikNCg0KIyBhc3NpZ24gdGF4b24gbmFtZSB0byBsaXN0IGVsZW1lbnRzDQojID4+IGZvciB0b3RhbCBkYXRhc2V0cw0KZm9yICh0YXhvbl9pZCBpbiAxOm5sZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKSl7DQogICMgZXh0cmFjdCAzLWxldHRlciBnZW51cyBuYW1lIHN0cmluZw0KICBhc3NpZ24ocGFzdGUwKHN0cl9leHRyYWN0KGxldmVscyhlbnZfY292X2Jpb19zdWIkdGF4b24pW3RheG9uX2lkXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIl5cXHd7M30iKSwNCiAgIyBleHRyYWN0IGFuZCBjYXBpdGFsaXNlIDMtbGV0dGVyIHNwZWNpZXMgbmFtZSBzdHJpbmcNCiAgICAgICAgICAgICAgICBzdHJfdG9fdGl0bGUoc3RyX3JlbW92ZShzdHJfZXh0cmFjdChsZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKVt0YXhvbl9pZF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxcc1xcd3szfSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcXHMiKSksDQogICMgYWRkIGV4dGVuc2lvbg0KICAgICAgICAgICAgICAgICIudG90IiksDQogICMgYXNzaWduIHRvIHJlc3BlY3RpdmUgbGlzdCBlbGVtZW50DQogICAgICAgICBlbnZfY292X2Jpb19zdWJfc3BlYy50b3RbW3RheG9uX2lkXV0pDQp9DQoNCg0KDQojID4+IGZvciBkaXNjcmV0ZSBkYXRhc2V0cw0KZW52X2Nvdl9iaW9fc3ViX3NwZWMuZGlzIDwtIGxpc3QoKQ0KZm9yICh0YXhvbl9pZCBpbiAxOm5sZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKSl7DQogICMgZmlsdGVyIGZvciBkaXNjcmV0ZSByZXNwb25zZSB2YWx1ZXMNCiAgZW52X2Nvdl9iaW9fc3ViX3NwZWMuZGlzW1t0YXhvbl9pZF1dIDwtIGZpbHRlcihlbnZfY292X2Jpb19zdWJfc3BlYy50b3RbW3RheG9uX2lkXV0sIGNvdmVyX2Rpc2NyZXRlID09IDEpDQogICMgZXh0cmFjdCAzLWxldHRlciBnZW51cyBuYW1lIHN0cmluZw0KICBhc3NpZ24ocGFzdGUwKHN0cl9leHRyYWN0KGxldmVscyhlbnZfY292X2Jpb19zdWIkdGF4b24pW3RheG9uX2lkXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIl5cXHd7M30iKSwNCiAgIyBleHRyYWN0IGFuZCBjYXBpdGFsaXNlIDMtbGV0dGVyIHNwZWNpZXMgbmFtZSBzdHJpbmcNCiAgICAgICAgICAgICAgICBzdHJfdG9fdGl0bGUoc3RyX3JlbW92ZShzdHJfZXh0cmFjdChsZXZlbHMoZW52X2Nvdl9iaW9fc3ViJHRheG9uKVt0YXhvbl9pZF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxcc1xcd3szfSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcXHMiKSksDQogICMgYWRkIGV4dGVuc2lvbg0KICAgICAgICAgICAgICAgICIuZGlzIiksDQogICMgYXNzaWduIHRvIHJlc3BlY3RpdmUgbGlzdCBlbGVtZW50DQogICAgICAgICBlbnZfY292X2Jpb19zdWJfc3BlYy5kaXNbW3RheG9uX2lkXV0pDQp9DQoNCiMgPj4gZm9yIGNvbnRpbnVvdXMgZGF0YXNldHMNCmVudl9jb3ZfYmlvX3N1Yl9zcGVjLmNvbnQgPC0gbGlzdCgpDQpmb3IgKHRheG9uX2lkIGluIDE6bmxldmVscyhlbnZfY292X2Jpb19zdWIkdGF4b24pKXsNCiAgIyBmaWx0ZXIgZm9yIGNvbnRpbnVvdXMgcmVzcG9uc2UgdmFsdWVzDQogIGVudl9jb3ZfYmlvX3N1Yl9zcGVjLmNvbnRbW3RheG9uX2lkXV0gPC0gZmlsdGVyKGVudl9jb3ZfYmlvX3N1Yl9zcGVjLnRvdFtbdGF4b25faWRdXSwgY292ZXJfZGlzY3JldGUgPT0gMCkNCiAgIyBleHRyYWN0IDMtbGV0dGVyIGdlbnVzIG5hbWUgc3RyaW5nDQogIGFzc2lnbihwYXN0ZTAoc3RyX2V4dHJhY3QobGV2ZWxzKGVudl9jb3ZfYmlvX3N1YiR0YXhvbilbdGF4b25faWRdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXlxcd3szfSIpLA0KICAjIGV4dHJhY3QgYW5kIGNhcGl0YWxpc2UgMy1sZXR0ZXIgc3BlY2llcyBuYW1lIHN0cmluZw0KICAgICAgICAgICAgICAgIHN0cl90b190aXRsZShzdHJfcmVtb3ZlKHN0cl9leHRyYWN0KGxldmVscyhlbnZfY292X2Jpb19zdWIkdGF4b24pW3RheG9uX2lkXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXFxzXFx3ezN9IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxccyIpKSwNCiAgIyBhZGQgZXh0ZW5zaW9uDQogICAgICAgICAgICAgICAgIi5jb250IiksDQogICMgYXNzaWduIHRvIHJlc3BlY3RpdmUgbGlzdCBlbGVtZW50DQogICAgICAgICBlbnZfY292X2Jpb19zdWJfc3BlYy5jb250W1t0YXhvbl9pZF1dKQ0KfQ0KDQpgYGANCg0KIyMjID4gYXNzZW1ibGluZyBkYXRhIGZvciBtb2RlbCBpbnB1dCBpbiBsaXN0cw0KDQpKQUdTIG5lZWRzIGRhdGEgaW5wdXQgaW4gbGlzdCBmb3JtYXQsIHNvIEkgcHJvdmlkZWQgYWxsIHJlbGV2YW50IHZhcmlhYmxlcyBhcyBmb2xsb3dzOg0KYGBge3J9DQojIENvbXBpbGUgZGF0YSBpbnRvIGxpc3RzDQojIEJldE5hbiAtLS0tDQpzaHJ1Yl9ncmFkaWVudF9qYWdzLkJldE5hbi5kYXRhIDwtIGxpc3QoDQogIA0KICAjIHBsb3QgbGV2ZWwgcHJlZGljdG9ycywgZm9yIGRpc2NyZXRlLi4uDQogIGNvdi5kaXMgPSBCZXROYW4uZGlzJGNvdmVyLA0KICBwbG90Z3JvdXAuZGlzID0gQmV0TmFuLmRpcyRwbG90Z3JvdXAuTlVNLCAjQUIgYWRkZWQgdGhpcw0KICAjIGlzb2NsaW5lLmRpcyA9IEJldE5hbi5kaXMkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmRpcyA9IEJldE5hbi5kaXMkaW5jbGluX2Rvd25DLA0KICBzcmkuZGlzID0gQmV0TmFuLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gQmV0TmFuLmRpcyR0cmlDLA0KICB0d2kuZGlzID0gQmV0TmFuLmRpcyR0d2lDLA0KICBjb21wZXQuZGlzID0gQmV0TmFuLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhCZXROYW4uZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IEJldE5hbi5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IEJldE5hbi5jb250JHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuY29udCA9IEJldE5hbi5jb250JHNpdGVfYWx0Lk5VTSwNCiAgIyBpbmNsaW5fZG93bi5jb250ID0gQmV0TmFuLmNvbnQkaW5jbGluX2Rvd25DLA0KICBzcmkuY29udCA9IEJldE5hbi5jb250JHNyaUMsDQogIHRyaS5jb250ID0gQmV0TmFuLmNvbnQkdHJpQywNCiAgdHdpLmNvbnQgPSBCZXROYW4uY29udCR0d2lDLA0KICBjb21wZXQuY29udCA9IEJldE5hbi5jb250JGNvbXBldEMsDQogIE5fY29udCA9IG5yb3coQmV0TmFuLmNvbnQpLA0KICANCiAgIyBwbG90IGdyb3VwIGxldmVsIHByZWRpY3RvcnMNCiAgdGVtcGpqYS50b3QgPSBCZXROYW4udG90JHRlbXBqamFfdHNfMzBDWyFkdXBsaWNhdGVkKEJldE5hbi50b3QkcGxvdGdyb3VwLk5VTSldLCAjIG9uZSB2YWx1ZSBwZXIgdFhwZw0KICAjIHRlbXBtYXgudG90ID0gQmV0TmFuLnRvdCR0ZW1wbWF4X3RzXzMwQ1shZHVwbGljYXRlZChCZXROYW4udG90JHBsb3Rncm91cC5OVU0pXSwNCiAgIyB0ZW1wbWluLnRvdCA9IEJldE5hbi50b3QkdGVtcG1pbl90c18zMENbIWR1cGxpY2F0ZWQoQmV0TmFuLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHRlbXBjb250LnRvdCA9IEJldE5hbi50b3QkdGVtcGNvbnRfdHNfMzBDWyFkdXBsaWNhdGVkKEJldE5hbi50b3QkcGxvdGdyb3VwLk5VTSldLA0KICBwcmVjaXBqamEudG90ID0gQmV0TmFuLnRvdCRwcmVjaXBqamFfdHNfMzBDWyFkdXBsaWNhdGVkKEJldE5hbi50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHByZWNpcGpmbWFtLnRvdCA9IEJldE5hbi50b3QkcHJlY2lwamZtYW1fdHNfMzBDWyFkdXBsaWNhdGVkKEJldE5hbi50b3QkcGxvdGdyb3VwLk5VTSldDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoQmV0TmFuLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgIyBzaXRlL2FsdCBsZXZlbCBwcmVkaWN0b3JzDQogICMgYWx0LnRvdCA9IEJldE5hbi50b3QkYWx0Q1shZHVwbGljYXRlZChCZXROYW4udG90JHNpdGVfYWx0Lk5VTSldLA0KICAjIE5faXNvY2xpbmVzID0gbGVuZ3RoKHVuaXF1ZShCZXROYW4udG90JHNpdGVfYWx0X2lkKSkNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoQmV0TmFuLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc3JpID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCRzcmlDKSwgdG8gPSBtYXgoQmV0TmFuLnRvdCRzcmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdHJpID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCR0cmlDKSwgdG8gPSBtYXgoQmV0TmFuLnRvdCR0cmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdHdpID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCR0d2lDKSwgdG8gPSBtYXgoQmV0TmFuLnRvdCR0d2lDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGpqYSA9IHNlcShmcm9tID0gbWluKEJldE5hbi50b3QkdGVtcGpqYV90c18zMEMpLCB0byA9IG1heChCZXROYW4udG90JHRlbXBqamFfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfcHJlY2lwamphID0gc2VxKGZyb20gPSBtaW4oQmV0TmFuLnRvdCRwcmVjaXBqamFfdHNfMzBDKSwgdG8gPSBtYXgoQmV0TmFuLnRvdCRwcmVjaXBqamFfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGNvbnQgPSBzZXEoZnJvbSA9IG1pbihCZXROYW4udG90JHRlbXBjb250X3RzXzMwQyksIHRvID0gbWF4KEJldE5hbi50b3QkdGVtcGNvbnRfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIE54aGF0ID0gMTAwLA0KICANCiAgIyAuLi4gYW5kIGZvciBwcmVkaWN0aW5nIGF0IGhpZ2gvbG93IHRlbXBlcmF0dXJlIGxldmVscw0KICB4aGF0X3RlbXBqamEyID0gYXMubnVtZXJpYyhjKHF1YW50aWxlKEJldE5hbi50b3QkdGVtcGpqYV90c18zMEMsMC4wNSkscXVhbnRpbGUoQmV0TmFuLnRvdCR0ZW1wamphX3RzXzMwQywwLjk1KSkpLCANCiAgTnhoYXQyID0gMg0KKQ0Kc3RyKHNocnViX2dyYWRpZW50X2phZ3MuQmV0TmFuLmRhdGEpDQoNCiMgQ2FzVGV0IC0tLS0NCnNocnViX2dyYWRpZW50X2phZ3MuQ2FzVGV0LmRhdGEgPC0gbGlzdCgNCiAgDQogICMgcGxvdCBsZXZlbCBwcmVkaWN0b3JzLCBmb3IgZGlzY3JldGUuLi4NCiAgY292LmRpcyA9IENhc1RldC5kaXMkY292ZXIsDQogIHBsb3Rncm91cC5kaXMgPSBDYXNUZXQuZGlzJHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuZGlzID0gQ2FzVGV0LmRpcyRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uZGlzID0gQ2FzVGV0LmRpcyRpbmNsaW5fZG93bkMsDQogIHNyaS5kaXMgPSBDYXNUZXQuZGlzJHNyaUMsDQogIHRyaS5kaXMgPSBDYXNUZXQuZGlzJHRyaUMsDQogIHR3aS5kaXMgPSBDYXNUZXQuZGlzJHR3aUMsDQogIGNvbXBldC5kaXMgPSBDYXNUZXQuZGlzJGNvbXBldEMsDQogIE5fZGlzY3JldGUgPSBucm93KENhc1RldC5kaXMpLA0KICANCiAgIyAuLi5hbmQgY29udGludW91cyBwYXJ0IG9mIHRoZSBkYXRhDQogIGNvdi5jb250ID0gQ2FzVGV0LmNvbnQkY292ZXIsDQogIHBsb3Rncm91cC5jb250ID0gQ2FzVGV0LmNvbnQkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5jb250ID0gQ2FzVGV0LmNvbnQkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmNvbnQgPSBDYXNUZXQuY29udCRpbmNsaW5fZG93bkMsDQogIHNyaS5jb250ID0gQ2FzVGV0LmNvbnQkc3JpQywNCiAgdHJpLmNvbnQgPSBDYXNUZXQuY29udCR0cmlDLA0KICB0d2kuY29udCA9IENhc1RldC5jb250JHR3aUMsDQogIGNvbXBldC5jb250ID0gQ2FzVGV0LmNvbnQkY29tcGV0QywNCiAgTl9jb250ID0gbnJvdyhDYXNUZXQuY29udCksDQogIA0KICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycw0KICB0ZW1wamphLnRvdCA9IENhc1RldC50b3QkdGVtcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoQ2FzVGV0LnRvdCRwbG90Z3JvdXAuTlVNKV0sICMgb25lIHZhbHVlIHBlciB0WHBnDQogICMgdGVtcG1heC50b3QgPSBDYXNUZXQudG90JHRlbXBtYXhfdHNfMzBDWyFkdXBsaWNhdGVkKENhc1RldC50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHRlbXBtaW4udG90ID0gQ2FzVGV0LnRvdCR0ZW1wbWluX3RzXzMwQ1shZHVwbGljYXRlZChDYXNUZXQudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgdGVtcGNvbnQudG90ID0gQ2FzVGV0LnRvdCR0ZW1wY29udF90c18zMENbIWR1cGxpY2F0ZWQoQ2FzVGV0LnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHByZWNpcGpqYS50b3QgPSBDYXNUZXQudG90JHByZWNpcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoQ2FzVGV0LnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgcHJlY2lwamZtYW0udG90ID0gQ2FzVGV0LnRvdCRwcmVjaXBqZm1hbV90c18zMENbIWR1cGxpY2F0ZWQoQ2FzVGV0LnRvdCRwbG90Z3JvdXAuTlVNKV0NCiAgTl9wbG90Z3JvdXBzID0gbGVuZ3RoKHVuaXF1ZShDYXNUZXQudG90JHNpdGVfYWx0X3Bsb3Rncm91cF9pZCkpLA0KICANCiAgIyAjIHNpdGUvYWx0IGxldmVsIHByZWRpY3RvcnMNCiAgIyBhbHQudG90ID0gQ2FzVGV0LnRvdCRhbHRDWyFkdXBsaWNhdGVkKENhc1RldC50b3Qkc2l0ZV9hbHQuTlVNKV0sDQogICMgTl9pc29jbGluZXMgPSBsZW5ndGgodW5pcXVlKENhc1RldC50b3Qkc2l0ZV9hbHRfaWQpKQ0KICANCiAgIyBzdWJzZXQgb2YgdmFsdWVzIGZvciBwcmVkaWN0aW9uLCBmb3IgZWFjaCBwcmVkaWN0b3IuLi4NCiAgeGhhdF9jb21wZXQgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JGNvbXBldEMpLCB0byA9IG1heChDYXNUZXQudG90JGNvbXBldEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JHNyaUMpLCB0byA9IG1heChDYXNUZXQudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JHRyaUMpLCB0byA9IG1heChDYXNUZXQudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90d2kgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JHR3aUMpLCB0byA9IG1heChDYXNUZXQudG90JHR3aUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oQ2FzVGV0LnRvdCR0ZW1wamphX3RzXzMwQyksIHRvID0gbWF4KENhc1RldC50b3QkdGVtcGpqYV90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihDYXNUZXQudG90JHByZWNpcGpqYV90c18zMEMpLCB0byA9IG1heChDYXNUZXQudG90JHByZWNpcGpqYV90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKENhc1RldC50b3QkdGVtcGNvbnRfdHNfMzBDKSwgdG8gPSBtYXgoQ2FzVGV0LnRvdCR0ZW1wY29udF90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGVtcGpqYTIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoQ2FzVGV0LnRvdCR0ZW1wamphX3RzXzMwQywwLjA1KSxxdWFudGlsZShDYXNUZXQudG90JHRlbXBqamFfdHNfMzBDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5DYXNUZXQuZGF0YSkNCg0KIyBFbXBOaWcgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5FbXBOaWcuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gRW1wTmlnLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IEVtcE5pZy5kaXMkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5kaXMgPSBFbXBOaWcuZGlzJHNpdGVfYWx0Lk5VTSwNCiAgIyBpbmNsaW5fZG93bi5kaXMgPSBFbXBOaWcuZGlzJGluY2xpbl9kb3duQywNCiAgc3JpLmRpcyA9IEVtcE5pZy5kaXMkc3JpQywNCiAgdHJpLmRpcyA9IEVtcE5pZy5kaXMkdHJpQywNCiAgdHdpLmRpcyA9IEVtcE5pZy5kaXMkdHdpQywNCiAgY29tcGV0LmRpcyA9IEVtcE5pZy5kaXMkY29tcGV0QywNCiAgTl9kaXNjcmV0ZSA9IG5yb3coRW1wTmlnLmRpcyksDQogIA0KICAjIC4uLmFuZCBjb250aW51b3VzIHBhcnQgb2YgdGhlIGRhdGENCiAgY292LmNvbnQgPSBFbXBOaWcuY29udCRjb3ZlciwNCiAgcGxvdGdyb3VwLmNvbnQgPSBFbXBOaWcuY29udCRwbG90Z3JvdXAuTlVNLCAjQUIgYWRkZWQgdGhpcw0KICAjIGlzb2NsaW5lLmNvbnQgPSBFbXBOaWcuY29udCRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uY29udCA9IEVtcE5pZy5jb250JGluY2xpbl9kb3duQywNCiAgc3JpLmNvbnQgPSBFbXBOaWcuY29udCRzcmlDLA0KICB0cmkuY29udCA9IEVtcE5pZy5jb250JHRyaUMsDQogIHR3aS5jb250ID0gRW1wTmlnLmNvbnQkdHdpQywNCiAgY29tcGV0LmNvbnQgPSBFbXBOaWcuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KEVtcE5pZy5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gRW1wTmlnLnRvdCR0ZW1wamphX3RzXzMwQ1shZHVwbGljYXRlZChFbXBOaWcudG90JHBsb3Rncm91cC5OVU0pXSwgIyBvbmUgdmFsdWUgcGVyIHRYcGcNCiAgIyB0ZW1wbWF4LnRvdCA9IEVtcE5pZy50b3QkdGVtcG1heF90c18zMENbIWR1cGxpY2F0ZWQoRW1wTmlnLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgdGVtcG1pbi50b3QgPSBFbXBOaWcudG90JHRlbXBtaW5fdHNfMzBDWyFkdXBsaWNhdGVkKEVtcE5pZy50b3QkcGxvdGdyb3VwLk5VTSldLA0KICB0ZW1wY29udC50b3QgPSBFbXBOaWcudG90JHRlbXBjb250X3RzXzMwQ1shZHVwbGljYXRlZChFbXBOaWcudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgcHJlY2lwamphLnRvdCA9IEVtcE5pZy50b3QkcHJlY2lwamphX3RzXzMwQ1shZHVwbGljYXRlZChFbXBOaWcudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgIyBwcmVjaXBqZm1hbS50b3QgPSBFbXBOaWcudG90JHByZWNpcGpmbWFtX3RzXzMwQ1shZHVwbGljYXRlZChFbXBOaWcudG90JHBsb3Rncm91cC5OVU0pXQ0KICBOX3Bsb3Rncm91cHMgPSBsZW5ndGgodW5pcXVlKEVtcE5pZy50b3Qkc2l0ZV9hbHRfcGxvdGdyb3VwX2lkKSksDQogIA0KICAjICMgc2l0ZS9hbHQgbGV2ZWwgcHJlZGljdG9ycw0KICAjIGFsdC50b3QgPSBFbXBOaWcudG90JGFsdENbIWR1cGxpY2F0ZWQoRW1wTmlnLnRvdCRzaXRlX2FsdC5OVU0pXSwNCiAgIyBOX2lzb2NsaW5lcyA9IGxlbmd0aCh1bmlxdWUoRW1wTmlnLnRvdCRzaXRlX2FsdF9pZCkpDQogIA0KICAjIHN1YnNldCBvZiB2YWx1ZXMgZm9yIHByZWRpY3Rpb24sIGZvciBlYWNoIHByZWRpY3Rvci4uLg0KICB4aGF0X2NvbXBldCA9IHNlcShmcm9tID0gbWluKEVtcE5pZy50b3QkY29tcGV0QyksIHRvID0gbWF4KEVtcE5pZy50b3QkY29tcGV0QyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3NyaSA9IHNlcShmcm9tID0gbWluKEVtcE5pZy50b3Qkc3JpQyksIHRvID0gbWF4KEVtcE5pZy50b3Qkc3JpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RyaSA9IHNlcShmcm9tID0gbWluKEVtcE5pZy50b3QkdHJpQyksIHRvID0gbWF4KEVtcE5pZy50b3QkdHJpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3R3aSA9IHNlcShmcm9tID0gbWluKEVtcE5pZy50b3QkdHdpQyksIHRvID0gbWF4KEVtcE5pZy50b3QkdHdpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBqamEgPSBzZXEoZnJvbSA9IG1pbihFbXBOaWcudG90JHRlbXBqamFfdHNfMzBDKSwgdG8gPSBtYXgoRW1wTmlnLnRvdCR0ZW1wamphX3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3ByZWNpcGpqYSA9IHNlcShmcm9tID0gbWluKEVtcE5pZy50b3QkcHJlY2lwamphX3RzXzMwQyksIHRvID0gbWF4KEVtcE5pZy50b3QkcHJlY2lwamphX3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBjb250ID0gc2VxKGZyb20gPSBtaW4oRW1wTmlnLnRvdCR0ZW1wY29udF90c18zMEMpLCB0byA9IG1heChFbXBOaWcudG90JHRlbXBjb250X3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICBOeGhhdCA9IDEwMCwNCiAgDQogICMgLi4uIGFuZCBmb3IgcHJlZGljdGluZyBhdCBoaWdoL2xvdyB0ZW1wZXJhdHVyZSBsZXZlbHMNCiAgeGhhdF90ZW1wamphMiA9IGFzLm51bWVyaWMoYyhxdWFudGlsZShFbXBOaWcudG90JHRlbXBqamFfdHNfMzBDLDAuMDUpLHF1YW50aWxlKEVtcE5pZy50b3QkdGVtcGpqYV90c18zMEMsMC45NSkpKSwgDQogIE54aGF0MiA9IDINCikNCnN0cihzaHJ1Yl9ncmFkaWVudF9qYWdzLkVtcE5pZy5kYXRhKQ0KDQojIFBoeUNhZSAtLS0tDQpzaHJ1Yl9ncmFkaWVudF9qYWdzLlBoeUNhZS5kYXRhIDwtIGxpc3QoDQogIA0KICAjIHBsb3QgbGV2ZWwgcHJlZGljdG9ycywgZm9yIGRpc2NyZXRlLi4uDQogIGNvdi5kaXMgPSBQaHlDYWUuZGlzJGNvdmVyLA0KICBwbG90Z3JvdXAuZGlzID0gUGh5Q2FlLmRpcyRwbG90Z3JvdXAuTlVNLCAjQUIgYWRkZWQgdGhpcw0KICAjIGlzb2NsaW5lLmRpcyA9IFBoeUNhZS5kaXMkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmRpcyA9IFBoeUNhZS5kaXMkaW5jbGluX2Rvd25DLA0KICBzcmkuZGlzID0gUGh5Q2FlLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gUGh5Q2FlLmRpcyR0cmlDLA0KICB0d2kuZGlzID0gUGh5Q2FlLmRpcyR0d2lDLA0KICBjb21wZXQuZGlzID0gUGh5Q2FlLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhQaHlDYWUuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFBoeUNhZS5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFBoeUNhZS5jb250JHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuY29udCA9IFBoeUNhZS5jb250JHNpdGVfYWx0Lk5VTSwNCiAgIyBpbmNsaW5fZG93bi5jb250ID0gUGh5Q2FlLmNvbnQkaW5jbGluX2Rvd25DLA0KICBzcmkuY29udCA9IFBoeUNhZS5jb250JHNyaUMsDQogIHRyaS5jb250ID0gUGh5Q2FlLmNvbnQkdHJpQywNCiAgdHdpLmNvbnQgPSBQaHlDYWUuY29udCR0d2lDLA0KICBjb21wZXQuY29udCA9IFBoeUNhZS5jb250JGNvbXBldEMsDQogIE5fY29udCA9IG5yb3coUGh5Q2FlLmNvbnQpLA0KICANCiAgIyBwbG90IGdyb3VwIGxldmVsIHByZWRpY3RvcnMNCiAgdGVtcGpqYS50b3QgPSBQaHlDYWUudG90JHRlbXBqamFfdHNfMzBDWyFkdXBsaWNhdGVkKFBoeUNhZS50b3QkcGxvdGdyb3VwLk5VTSldLCAjIG9uZSB2YWx1ZSBwZXIgdFhwZw0KICAjIHRlbXBtYXgudG90ID0gUGh5Q2FlLnRvdCR0ZW1wbWF4X3RzXzMwQ1shZHVwbGljYXRlZChQaHlDYWUudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgIyB0ZW1wbWluLnRvdCA9IFBoeUNhZS50b3QkdGVtcG1pbl90c18zMENbIWR1cGxpY2F0ZWQoUGh5Q2FlLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHRlbXBjb250LnRvdCA9IFBoeUNhZS50b3QkdGVtcGNvbnRfdHNfMzBDWyFkdXBsaWNhdGVkKFBoeUNhZS50b3QkcGxvdGdyb3VwLk5VTSldLA0KICBwcmVjaXBqamEudG90ID0gUGh5Q2FlLnRvdCRwcmVjaXBqamFfdHNfMzBDWyFkdXBsaWNhdGVkKFBoeUNhZS50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHByZWNpcGpmbWFtLnRvdCA9IFBoeUNhZS50b3QkcHJlY2lwamZtYW1fdHNfMzBDWyFkdXBsaWNhdGVkKFBoeUNhZS50b3QkcGxvdGdyb3VwLk5VTSldDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoUGh5Q2FlLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgIyBzaXRlL2FsdCBsZXZlbCBwcmVkaWN0b3JzDQogICMgYWx0LnRvdCA9IFBoeUNhZS50b3QkYWx0Q1shZHVwbGljYXRlZChQaHlDYWUudG90JHNpdGVfYWx0Lk5VTSldLA0KICAjIE5faXNvY2xpbmVzID0gbGVuZ3RoKHVuaXF1ZShQaHlDYWUudG90JHNpdGVfYWx0X2lkKSkNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoUGh5Q2FlLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc3JpID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCRzcmlDKSwgdG8gPSBtYXgoUGh5Q2FlLnRvdCRzcmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdHJpID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCR0cmlDKSwgdG8gPSBtYXgoUGh5Q2FlLnRvdCR0cmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdHdpID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCR0d2lDKSwgdG8gPSBtYXgoUGh5Q2FlLnRvdCR0d2lDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGpqYSA9IHNlcShmcm9tID0gbWluKFBoeUNhZS50b3QkdGVtcGpqYV90c18zMEMpLCB0byA9IG1heChQaHlDYWUudG90JHRlbXBqamFfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfcHJlY2lwamphID0gc2VxKGZyb20gPSBtaW4oUGh5Q2FlLnRvdCRwcmVjaXBqamFfdHNfMzBDKSwgdG8gPSBtYXgoUGh5Q2FlLnRvdCRwcmVjaXBqamFfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGNvbnQgPSBzZXEoZnJvbSA9IG1pbihQaHlDYWUudG90JHRlbXBjb250X3RzXzMwQyksIHRvID0gbWF4KFBoeUNhZS50b3QkdGVtcGNvbnRfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIE54aGF0ID0gMTAwLA0KICANCiAgIyAuLi4gYW5kIGZvciBwcmVkaWN0aW5nIGF0IGhpZ2gvbG93IHRlbXBlcmF0dXJlIGxldmVscw0KICB4aGF0X3RlbXBqamEyID0gYXMubnVtZXJpYyhjKHF1YW50aWxlKFBoeUNhZS50b3QkdGVtcGpqYV90c18zMEMsMC4wNSkscXVhbnRpbGUoUGh5Q2FlLnRvdCR0ZW1wamphX3RzXzMwQywwLjk1KSkpLCANCiAgTnhoYXQyID0gMg0KKQ0Kc3RyKHNocnViX2dyYWRpZW50X2phZ3MuUGh5Q2FlLmRhdGEpDQoNCiMgUmhvR3JvIC0tLS0NCnNocnViX2dyYWRpZW50X2phZ3MuUmhvR3JvLmRhdGEgPC0gbGlzdCgNCiAgDQogICMgcGxvdCBsZXZlbCBwcmVkaWN0b3JzLCBmb3IgZGlzY3JldGUuLi4NCiAgY292LmRpcyA9IFJob0dyby5kaXMkY292ZXIsDQogIHBsb3Rncm91cC5kaXMgPSBSaG9Hcm8uZGlzJHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuZGlzID0gUmhvR3JvLmRpcyRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uZGlzID0gUmhvR3JvLmRpcyRpbmNsaW5fZG93bkMsDQogIHNyaS5kaXMgPSBSaG9Hcm8uZGlzJHNyaUMsDQogIHRyaS5kaXMgPSBSaG9Hcm8uZGlzJHRyaUMsDQogIHR3aS5kaXMgPSBSaG9Hcm8uZGlzJHR3aUMsDQogIGNvbXBldC5kaXMgPSBSaG9Hcm8uZGlzJGNvbXBldEMsDQogIE5fZGlzY3JldGUgPSBucm93KFJob0dyby5kaXMpLA0KICANCiAgIyAuLi5hbmQgY29udGludW91cyBwYXJ0IG9mIHRoZSBkYXRhDQogIGNvdi5jb250ID0gUmhvR3JvLmNvbnQkY292ZXIsDQogIHBsb3Rncm91cC5jb250ID0gUmhvR3JvLmNvbnQkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5jb250ID0gUmhvR3JvLmNvbnQkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmNvbnQgPSBSaG9Hcm8uY29udCRpbmNsaW5fZG93bkMsDQogIHNyaS5jb250ID0gUmhvR3JvLmNvbnQkc3JpQywNCiAgdHJpLmNvbnQgPSBSaG9Hcm8uY29udCR0cmlDLA0KICB0d2kuY29udCA9IFJob0dyby5jb250JHR3aUMsDQogIGNvbXBldC5jb250ID0gUmhvR3JvLmNvbnQkY29tcGV0QywNCiAgTl9jb250ID0gbnJvdyhSaG9Hcm8uY29udCksDQogIA0KICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycw0KICB0ZW1wamphLnRvdCA9IFJob0dyby50b3QkdGVtcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoUmhvR3JvLnRvdCRwbG90Z3JvdXAuTlVNKV0sICMgb25lIHZhbHVlIHBlciB0WHBnDQogICMgdGVtcG1heC50b3QgPSBSaG9Hcm8udG90JHRlbXBtYXhfdHNfMzBDWyFkdXBsaWNhdGVkKFJob0dyby50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHRlbXBtaW4udG90ID0gUmhvR3JvLnRvdCR0ZW1wbWluX3RzXzMwQ1shZHVwbGljYXRlZChSaG9Hcm8udG90JHBsb3Rncm91cC5OVU0pXSwNCiAgdGVtcGNvbnQudG90ID0gUmhvR3JvLnRvdCR0ZW1wY29udF90c18zMENbIWR1cGxpY2F0ZWQoUmhvR3JvLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHByZWNpcGpqYS50b3QgPSBSaG9Hcm8udG90JHByZWNpcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoUmhvR3JvLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgcHJlY2lwamZtYW0udG90ID0gUmhvR3JvLnRvdCRwcmVjaXBqZm1hbV90c18zMENbIWR1cGxpY2F0ZWQoUmhvR3JvLnRvdCRwbG90Z3JvdXAuTlVNKV0NCiAgTl9wbG90Z3JvdXBzID0gbGVuZ3RoKHVuaXF1ZShSaG9Hcm8udG90JHNpdGVfYWx0X3Bsb3Rncm91cF9pZCkpLA0KICANCiAgIyAjIHNpdGUvYWx0IGxldmVsIHByZWRpY3RvcnMNCiAgIyBhbHQudG90ID0gUmhvR3JvLnRvdCRhbHRDWyFkdXBsaWNhdGVkKFJob0dyby50b3Qkc2l0ZV9hbHQuTlVNKV0sDQogICMgTl9pc29jbGluZXMgPSBsZW5ndGgodW5pcXVlKFJob0dyby50b3Qkc2l0ZV9hbHRfaWQpKQ0KICANCiAgIyBzdWJzZXQgb2YgdmFsdWVzIGZvciBwcmVkaWN0aW9uLCBmb3IgZWFjaCBwcmVkaWN0b3IuLi4NCiAgeGhhdF9jb21wZXQgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JGNvbXBldEMpLCB0byA9IG1heChSaG9Hcm8udG90JGNvbXBldEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JHNyaUMpLCB0byA9IG1heChSaG9Hcm8udG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JHRyaUMpLCB0byA9IG1heChSaG9Hcm8udG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90d2kgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JHR3aUMpLCB0byA9IG1heChSaG9Hcm8udG90JHR3aUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oUmhvR3JvLnRvdCR0ZW1wamphX3RzXzMwQyksIHRvID0gbWF4KFJob0dyby50b3QkdGVtcGpqYV90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihSaG9Hcm8udG90JHByZWNpcGpqYV90c18zMEMpLCB0byA9IG1heChSaG9Hcm8udG90JHByZWNpcGpqYV90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFJob0dyby50b3QkdGVtcGNvbnRfdHNfMzBDKSwgdG8gPSBtYXgoUmhvR3JvLnRvdCR0ZW1wY29udF90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGVtcGpqYTIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoUmhvR3JvLnRvdCR0ZW1wamphX3RzXzMwQywwLjA1KSxxdWFudGlsZShSaG9Hcm8udG90JHRlbXBqamFfdHNfMzBDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5SaG9Hcm8uZGF0YSkNCg0KIyBSaG9Ub20gLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5SaG9Ub20uZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gUmhvVG9tLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFJob1RvbS5kaXMkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5kaXMgPSBSaG9Ub20uZGlzJHNpdGVfYWx0Lk5VTSwNCiAgIyBpbmNsaW5fZG93bi5kaXMgPSBSaG9Ub20uZGlzJGluY2xpbl9kb3duQywNCiAgc3JpLmRpcyA9IFJob1RvbS5kaXMkc3JpQywNCiAgdHJpLmRpcyA9IFJob1RvbS5kaXMkdHJpQywNCiAgdHdpLmRpcyA9IFJob1RvbS5kaXMkdHdpQywNCiAgY29tcGV0LmRpcyA9IFJob1RvbS5kaXMkY29tcGV0QywNCiAgTl9kaXNjcmV0ZSA9IG5yb3coUmhvVG9tLmRpcyksDQogIA0KICAjIC4uLmFuZCBjb250aW51b3VzIHBhcnQgb2YgdGhlIGRhdGENCiAgY292LmNvbnQgPSBSaG9Ub20uY29udCRjb3ZlciwNCiAgcGxvdGdyb3VwLmNvbnQgPSBSaG9Ub20uY29udCRwbG90Z3JvdXAuTlVNLCAjQUIgYWRkZWQgdGhpcw0KICAjIGlzb2NsaW5lLmNvbnQgPSBSaG9Ub20uY29udCRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uY29udCA9IFJob1RvbS5jb250JGluY2xpbl9kb3duQywNCiAgc3JpLmNvbnQgPSBSaG9Ub20uY29udCRzcmlDLA0KICB0cmkuY29udCA9IFJob1RvbS5jb250JHRyaUMsDQogIHR3aS5jb250ID0gUmhvVG9tLmNvbnQkdHdpQywNCiAgY29tcGV0LmNvbnQgPSBSaG9Ub20uY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFJob1RvbS5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gUmhvVG9tLnRvdCR0ZW1wamphX3RzXzMwQ1shZHVwbGljYXRlZChSaG9Ub20udG90JHBsb3Rncm91cC5OVU0pXSwgIyBvbmUgdmFsdWUgcGVyIHRYcGcNCiAgIyB0ZW1wbWF4LnRvdCA9IFJob1RvbS50b3QkdGVtcG1heF90c18zMENbIWR1cGxpY2F0ZWQoUmhvVG9tLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgdGVtcG1pbi50b3QgPSBSaG9Ub20udG90JHRlbXBtaW5fdHNfMzBDWyFkdXBsaWNhdGVkKFJob1RvbS50b3QkcGxvdGdyb3VwLk5VTSldLA0KICB0ZW1wY29udC50b3QgPSBSaG9Ub20udG90JHRlbXBjb250X3RzXzMwQ1shZHVwbGljYXRlZChSaG9Ub20udG90JHBsb3Rncm91cC5OVU0pXSwNCiAgcHJlY2lwamphLnRvdCA9IFJob1RvbS50b3QkcHJlY2lwamphX3RzXzMwQ1shZHVwbGljYXRlZChSaG9Ub20udG90JHBsb3Rncm91cC5OVU0pXSwNCiAgIyBwcmVjaXBqZm1hbS50b3QgPSBSaG9Ub20udG90JHByZWNpcGpmbWFtX3RzXzMwQ1shZHVwbGljYXRlZChSaG9Ub20udG90JHBsb3Rncm91cC5OVU0pXQ0KICBOX3Bsb3Rncm91cHMgPSBsZW5ndGgodW5pcXVlKFJob1RvbS50b3Qkc2l0ZV9hbHRfcGxvdGdyb3VwX2lkKSksDQogIA0KICAjICMgc2l0ZS9hbHQgbGV2ZWwgcHJlZGljdG9ycw0KICAjIGFsdC50b3QgPSBSaG9Ub20udG90JGFsdENbIWR1cGxpY2F0ZWQoUmhvVG9tLnRvdCRzaXRlX2FsdC5OVU0pXSwNCiAgIyBOX2lzb2NsaW5lcyA9IGxlbmd0aCh1bmlxdWUoUmhvVG9tLnRvdCRzaXRlX2FsdF9pZCkpDQogIA0KICAjIHN1YnNldCBvZiB2YWx1ZXMgZm9yIHByZWRpY3Rpb24sIGZvciBlYWNoIHByZWRpY3Rvci4uLg0KICB4aGF0X2NvbXBldCA9IHNlcShmcm9tID0gbWluKFJob1RvbS50b3QkY29tcGV0QyksIHRvID0gbWF4KFJob1RvbS50b3QkY29tcGV0QyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3NyaSA9IHNlcShmcm9tID0gbWluKFJob1RvbS50b3Qkc3JpQyksIHRvID0gbWF4KFJob1RvbS50b3Qkc3JpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RyaSA9IHNlcShmcm9tID0gbWluKFJob1RvbS50b3QkdHJpQyksIHRvID0gbWF4KFJob1RvbS50b3QkdHJpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3R3aSA9IHNlcShmcm9tID0gbWluKFJob1RvbS50b3QkdHdpQyksIHRvID0gbWF4KFJob1RvbS50b3QkdHdpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBqamEgPSBzZXEoZnJvbSA9IG1pbihSaG9Ub20udG90JHRlbXBqamFfdHNfMzBDKSwgdG8gPSBtYXgoUmhvVG9tLnRvdCR0ZW1wamphX3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3ByZWNpcGpqYSA9IHNlcShmcm9tID0gbWluKFJob1RvbS50b3QkcHJlY2lwamphX3RzXzMwQyksIHRvID0gbWF4KFJob1RvbS50b3QkcHJlY2lwamphX3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBjb250ID0gc2VxKGZyb20gPSBtaW4oUmhvVG9tLnRvdCR0ZW1wY29udF90c18zMEMpLCB0byA9IG1heChSaG9Ub20udG90JHRlbXBjb250X3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICBOeGhhdCA9IDEwMCwNCiAgDQogICMgLi4uIGFuZCBmb3IgcHJlZGljdGluZyBhdCBoaWdoL2xvdyB0ZW1wZXJhdHVyZSBsZXZlbHMNCiAgeGhhdF90ZW1wamphMiA9IGFzLm51bWVyaWMoYyhxdWFudGlsZShSaG9Ub20udG90JHRlbXBqamFfdHNfMzBDLDAuMDUpLHF1YW50aWxlKFJob1RvbS50b3QkdGVtcGpqYV90c18zMEMsMC45NSkpKSwgDQogIE54aGF0MiA9IDINCikNCnN0cihzaHJ1Yl9ncmFkaWVudF9qYWdzLlJob1RvbS5kYXRhKQ0KDQojIFNhbEFyYyAtLS0tDQpzaHJ1Yl9ncmFkaWVudF9qYWdzLlNhbEFyYy5kYXRhIDwtIGxpc3QoDQogIA0KICAjIHBsb3QgbGV2ZWwgcHJlZGljdG9ycywgZm9yIGRpc2NyZXRlLi4uDQogIGNvdi5kaXMgPSBTYWxBcmMuZGlzJGNvdmVyLA0KICBwbG90Z3JvdXAuZGlzID0gU2FsQXJjLmRpcyRwbG90Z3JvdXAuTlVNLCAjQUIgYWRkZWQgdGhpcw0KICAjIGlzb2NsaW5lLmRpcyA9IFNhbEFyYy5kaXMkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmRpcyA9IFNhbEFyYy5kaXMkaW5jbGluX2Rvd25DLA0KICBzcmkuZGlzID0gU2FsQXJjLmRpcyRzcmlDLA0KICB0cmkuZGlzID0gU2FsQXJjLmRpcyR0cmlDLA0KICB0d2kuZGlzID0gU2FsQXJjLmRpcyR0d2lDLA0KICBjb21wZXQuZGlzID0gU2FsQXJjLmRpcyRjb21wZXRDLA0KICBOX2Rpc2NyZXRlID0gbnJvdyhTYWxBcmMuZGlzKSwNCiAgDQogICMgLi4uYW5kIGNvbnRpbnVvdXMgcGFydCBvZiB0aGUgZGF0YQ0KICBjb3YuY29udCA9IFNhbEFyYy5jb250JGNvdmVyLA0KICBwbG90Z3JvdXAuY29udCA9IFNhbEFyYy5jb250JHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuY29udCA9IFNhbEFyYy5jb250JHNpdGVfYWx0Lk5VTSwNCiAgIyBpbmNsaW5fZG93bi5jb250ID0gU2FsQXJjLmNvbnQkaW5jbGluX2Rvd25DLA0KICBzcmkuY29udCA9IFNhbEFyYy5jb250JHNyaUMsDQogIHRyaS5jb250ID0gU2FsQXJjLmNvbnQkdHJpQywNCiAgdHdpLmNvbnQgPSBTYWxBcmMuY29udCR0d2lDLA0KICBjb21wZXQuY29udCA9IFNhbEFyYy5jb250JGNvbXBldEMsDQogIE5fY29udCA9IG5yb3coU2FsQXJjLmNvbnQpLA0KICANCiAgIyBwbG90IGdyb3VwIGxldmVsIHByZWRpY3RvcnMNCiAgdGVtcGpqYS50b3QgPSBTYWxBcmMudG90JHRlbXBqamFfdHNfMzBDWyFkdXBsaWNhdGVkKFNhbEFyYy50b3QkcGxvdGdyb3VwLk5VTSldLCAjIG9uZSB2YWx1ZSBwZXIgdFhwZw0KICAjIHRlbXBtYXgudG90ID0gU2FsQXJjLnRvdCR0ZW1wbWF4X3RzXzMwQ1shZHVwbGljYXRlZChTYWxBcmMudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgIyB0ZW1wbWluLnRvdCA9IFNhbEFyYy50b3QkdGVtcG1pbl90c18zMENbIWR1cGxpY2F0ZWQoU2FsQXJjLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHRlbXBjb250LnRvdCA9IFNhbEFyYy50b3QkdGVtcGNvbnRfdHNfMzBDWyFkdXBsaWNhdGVkKFNhbEFyYy50b3QkcGxvdGdyb3VwLk5VTSldLA0KICBwcmVjaXBqamEudG90ID0gU2FsQXJjLnRvdCRwcmVjaXBqamFfdHNfMzBDWyFkdXBsaWNhdGVkKFNhbEFyYy50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHByZWNpcGpmbWFtLnRvdCA9IFNhbEFyYy50b3QkcHJlY2lwamZtYW1fdHNfMzBDWyFkdXBsaWNhdGVkKFNhbEFyYy50b3QkcGxvdGdyb3VwLk5VTSldDQogIE5fcGxvdGdyb3VwcyA9IGxlbmd0aCh1bmlxdWUoU2FsQXJjLnRvdCRzaXRlX2FsdF9wbG90Z3JvdXBfaWQpKSwNCiAgDQogICMgIyBzaXRlL2FsdCBsZXZlbCBwcmVkaWN0b3JzDQogICMgYWx0LnRvdCA9IFNhbEFyYy50b3QkYWx0Q1shZHVwbGljYXRlZChTYWxBcmMudG90JHNpdGVfYWx0Lk5VTSldLA0KICAjIE5faXNvY2xpbmVzID0gbGVuZ3RoKHVuaXF1ZShTYWxBcmMudG90JHNpdGVfYWx0X2lkKSkNCiAgDQogICMgc3Vic2V0IG9mIHZhbHVlcyBmb3IgcHJlZGljdGlvbiwgZm9yIGVhY2ggcHJlZGljdG9yLi4uDQogIHhoYXRfY29tcGV0ID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCRjb21wZXRDKSwgdG8gPSBtYXgoU2FsQXJjLnRvdCRjb21wZXRDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfc3JpID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCRzcmlDKSwgdG8gPSBtYXgoU2FsQXJjLnRvdCRzcmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdHJpID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCR0cmlDKSwgdG8gPSBtYXgoU2FsQXJjLnRvdCR0cmlDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdHdpID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCR0d2lDKSwgdG8gPSBtYXgoU2FsQXJjLnRvdCR0d2lDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGpqYSA9IHNlcShmcm9tID0gbWluKFNhbEFyYy50b3QkdGVtcGpqYV90c18zMEMpLCB0byA9IG1heChTYWxBcmMudG90JHRlbXBqamFfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfcHJlY2lwamphID0gc2VxKGZyb20gPSBtaW4oU2FsQXJjLnRvdCRwcmVjaXBqamFfdHNfMzBDKSwgdG8gPSBtYXgoU2FsQXJjLnRvdCRwcmVjaXBqamFfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIHhoYXRfdGVtcGNvbnQgPSBzZXEoZnJvbSA9IG1pbihTYWxBcmMudG90JHRlbXBjb250X3RzXzMwQyksIHRvID0gbWF4KFNhbEFyYy50b3QkdGVtcGNvbnRfdHNfMzBDKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogIE54aGF0ID0gMTAwLA0KICANCiAgIyAuLi4gYW5kIGZvciBwcmVkaWN0aW5nIGF0IGhpZ2gvbG93IHRlbXBlcmF0dXJlIGxldmVscw0KICB4aGF0X3RlbXBqamEyID0gYXMubnVtZXJpYyhjKHF1YW50aWxlKFNhbEFyYy50b3QkdGVtcGpqYV90c18zMEMsMC4wNSkscXVhbnRpbGUoU2FsQXJjLnRvdCR0ZW1wamphX3RzXzMwQywwLjk1KSkpLCANCiAgTnhoYXQyID0gMg0KKQ0Kc3RyKHNocnViX2dyYWRpZW50X2phZ3MuU2FsQXJjLmRhdGEpDQoNCiMgU2FsR2xhIC0tLS0NCnNocnViX2dyYWRpZW50X2phZ3MuU2FsR2xhLmRhdGEgPC0gbGlzdCgNCiAgDQogICMgcGxvdCBsZXZlbCBwcmVkaWN0b3JzLCBmb3IgZGlzY3JldGUuLi4NCiAgY292LmRpcyA9IFNhbEdsYS5kaXMkY292ZXIsDQogIHBsb3Rncm91cC5kaXMgPSBTYWxHbGEuZGlzJHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuZGlzID0gU2FsR2xhLmRpcyRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uZGlzID0gU2FsR2xhLmRpcyRpbmNsaW5fZG93bkMsDQogIHNyaS5kaXMgPSBTYWxHbGEuZGlzJHNyaUMsDQogIHRyaS5kaXMgPSBTYWxHbGEuZGlzJHRyaUMsDQogIHR3aS5kaXMgPSBTYWxHbGEuZGlzJHR3aUMsDQogIGNvbXBldC5kaXMgPSBTYWxHbGEuZGlzJGNvbXBldEMsDQogIE5fZGlzY3JldGUgPSBucm93KFNhbEdsYS5kaXMpLA0KICANCiAgIyAuLi5hbmQgY29udGludW91cyBwYXJ0IG9mIHRoZSBkYXRhDQogIGNvdi5jb250ID0gU2FsR2xhLmNvbnQkY292ZXIsDQogIHBsb3Rncm91cC5jb250ID0gU2FsR2xhLmNvbnQkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5jb250ID0gU2FsR2xhLmNvbnQkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmNvbnQgPSBTYWxHbGEuY29udCRpbmNsaW5fZG93bkMsDQogIHNyaS5jb250ID0gU2FsR2xhLmNvbnQkc3JpQywNCiAgdHJpLmNvbnQgPSBTYWxHbGEuY29udCR0cmlDLA0KICB0d2kuY29udCA9IFNhbEdsYS5jb250JHR3aUMsDQogIGNvbXBldC5jb250ID0gU2FsR2xhLmNvbnQkY29tcGV0QywNCiAgTl9jb250ID0gbnJvdyhTYWxHbGEuY29udCksDQogIA0KICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycw0KICB0ZW1wamphLnRvdCA9IFNhbEdsYS50b3QkdGVtcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0sICMgb25lIHZhbHVlIHBlciB0WHBnDQogICMgdGVtcG1heC50b3QgPSBTYWxHbGEudG90JHRlbXBtYXhfdHNfMzBDWyFkdXBsaWNhdGVkKFNhbEdsYS50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHRlbXBtaW4udG90ID0gU2FsR2xhLnRvdCR0ZW1wbWluX3RzXzMwQ1shZHVwbGljYXRlZChTYWxHbGEudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgdGVtcGNvbnQudG90ID0gU2FsR2xhLnRvdCR0ZW1wY29udF90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHByZWNpcGpqYS50b3QgPSBTYWxHbGEudG90JHByZWNpcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgcHJlY2lwamZtYW0udG90ID0gU2FsR2xhLnRvdCRwcmVjaXBqZm1hbV90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0NCiAgTl9wbG90Z3JvdXBzID0gbGVuZ3RoKHVuaXF1ZShTYWxHbGEudG90JHNpdGVfYWx0X3Bsb3Rncm91cF9pZCkpLA0KICANCiAgIyAjIHNpdGUvYWx0IGxldmVsIHByZWRpY3RvcnMNCiAgIyBhbHQudG90ID0gU2FsR2xhLnRvdCRhbHRDWyFkdXBsaWNhdGVkKFNhbEdsYS50b3Qkc2l0ZV9hbHQuTlVNKV0sDQogICMgTl9pc29jbGluZXMgPSBsZW5ndGgodW5pcXVlKFNhbEdsYS50b3Qkc2l0ZV9hbHRfaWQpKQ0KICANCiAgIyBzdWJzZXQgb2YgdmFsdWVzIGZvciBwcmVkaWN0aW9uLCBmb3IgZWFjaCBwcmVkaWN0b3IuLi4NCiAgeGhhdF9jb21wZXQgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JGNvbXBldEMpLCB0byA9IG1heChTYWxHbGEudG90JGNvbXBldEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9zcmkgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JHNyaUMpLCB0byA9IG1heChTYWxHbGEudG90JHNyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90cmkgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JHRyaUMpLCB0byA9IG1heChTYWxHbGEudG90JHRyaUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90d2kgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JHR3aUMpLCB0byA9IG1heChTYWxHbGEudG90JHR3aUMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wamphID0gc2VxKGZyb20gPSBtaW4oU2FsR2xhLnRvdCR0ZW1wamphX3RzXzMwQyksIHRvID0gbWF4KFNhbEdsYS50b3QkdGVtcGpqYV90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF9wcmVjaXBqamEgPSBzZXEoZnJvbSA9IG1pbihTYWxHbGEudG90JHByZWNpcGpqYV90c18zMEMpLCB0byA9IG1heChTYWxHbGEudG90JHByZWNpcGpqYV90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgeGhhdF90ZW1wY29udCA9IHNlcShmcm9tID0gbWluKFNhbEdsYS50b3QkdGVtcGNvbnRfdHNfMzBDKSwgdG8gPSBtYXgoU2FsR2xhLnRvdCR0ZW1wY29udF90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDAsDQogIA0KICAjIC4uLiBhbmQgZm9yIHByZWRpY3RpbmcgYXQgaGlnaC9sb3cgdGVtcGVyYXR1cmUgbGV2ZWxzDQogIHhoYXRfdGVtcGpqYTIgPSBhcy5udW1lcmljKGMocXVhbnRpbGUoU2FsR2xhLnRvdCR0ZW1wamphX3RzXzMwQywwLjA1KSxxdWFudGlsZShTYWxHbGEudG90JHRlbXBqamFfdHNfMzBDLDAuOTUpKSksIA0KICBOeGhhdDIgPSAyDQopDQpzdHIoc2hydWJfZ3JhZGllbnRfamFncy5TYWxHbGEuZGF0YSkNCg0KIyBWYWNVbGkgLS0tLQ0Kc2hydWJfZ3JhZGllbnRfamFncy5WYWNVbGkuZGF0YSA8LSBsaXN0KA0KICANCiAgIyBwbG90IGxldmVsIHByZWRpY3RvcnMsIGZvciBkaXNjcmV0ZS4uLg0KICBjb3YuZGlzID0gVmFjVWxpLmRpcyRjb3ZlciwNCiAgcGxvdGdyb3VwLmRpcyA9IFZhY1VsaS5kaXMkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5kaXMgPSBWYWNVbGkuZGlzJHNpdGVfYWx0Lk5VTSwNCiAgIyBpbmNsaW5fZG93bi5kaXMgPSBWYWNVbGkuZGlzJGluY2xpbl9kb3duQywNCiAgc3JpLmRpcyA9IFZhY1VsaS5kaXMkc3JpQywNCiAgdHJpLmRpcyA9IFZhY1VsaS5kaXMkdHJpQywNCiAgdHdpLmRpcyA9IFZhY1VsaS5kaXMkdHdpQywNCiAgY29tcGV0LmRpcyA9IFZhY1VsaS5kaXMkY29tcGV0QywNCiAgTl9kaXNjcmV0ZSA9IG5yb3coVmFjVWxpLmRpcyksDQogIA0KICAjIC4uLmFuZCBjb250aW51b3VzIHBhcnQgb2YgdGhlIGRhdGENCiAgY292LmNvbnQgPSBWYWNVbGkuY29udCRjb3ZlciwNCiAgcGxvdGdyb3VwLmNvbnQgPSBWYWNVbGkuY29udCRwbG90Z3JvdXAuTlVNLCAjQUIgYWRkZWQgdGhpcw0KICAjIGlzb2NsaW5lLmNvbnQgPSBWYWNVbGkuY29udCRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uY29udCA9IFZhY1VsaS5jb250JGluY2xpbl9kb3duQywNCiAgc3JpLmNvbnQgPSBWYWNVbGkuY29udCRzcmlDLA0KICB0cmkuY29udCA9IFZhY1VsaS5jb250JHRyaUMsDQogIHR3aS5jb250ID0gVmFjVWxpLmNvbnQkdHdpQywNCiAgY29tcGV0LmNvbnQgPSBWYWNVbGkuY29udCRjb21wZXRDLA0KICBOX2NvbnQgPSBucm93KFZhY1VsaS5jb250KSwNCiAgDQogICMgcGxvdCBncm91cCBsZXZlbCBwcmVkaWN0b3JzDQogIHRlbXBqamEudG90ID0gVmFjVWxpLnRvdCR0ZW1wamphX3RzXzMwQ1shZHVwbGljYXRlZChWYWNVbGkudG90JHBsb3Rncm91cC5OVU0pXSwgIyBvbmUgdmFsdWUgcGVyIHRYcGcNCiAgIyB0ZW1wbWF4LnRvdCA9IFZhY1VsaS50b3QkdGVtcG1heF90c18zMENbIWR1cGxpY2F0ZWQoVmFjVWxpLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgdGVtcG1pbi50b3QgPSBWYWNVbGkudG90JHRlbXBtaW5fdHNfMzBDWyFkdXBsaWNhdGVkKFZhY1VsaS50b3QkcGxvdGdyb3VwLk5VTSldLA0KICB0ZW1wY29udC50b3QgPSBWYWNVbGkudG90JHRlbXBjb250X3RzXzMwQ1shZHVwbGljYXRlZChWYWNVbGkudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgcHJlY2lwamphLnRvdCA9IFZhY1VsaS50b3QkcHJlY2lwamphX3RzXzMwQ1shZHVwbGljYXRlZChWYWNVbGkudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgIyBwcmVjaXBqZm1hbS50b3QgPSBWYWNVbGkudG90JHByZWNpcGpmbWFtX3RzXzMwQ1shZHVwbGljYXRlZChWYWNVbGkudG90JHBsb3Rncm91cC5OVU0pXQ0KICBOX3Bsb3Rncm91cHMgPSBsZW5ndGgodW5pcXVlKFZhY1VsaS50b3Qkc2l0ZV9hbHRfcGxvdGdyb3VwX2lkKSksDQogIA0KICAjICMgc2l0ZS9hbHQgbGV2ZWwgcHJlZGljdG9ycw0KICAjIGFsdC50b3QgPSBWYWNVbGkudG90JGFsdENbIWR1cGxpY2F0ZWQoVmFjVWxpLnRvdCRzaXRlX2FsdC5OVU0pXSwNCiAgIyBOX2lzb2NsaW5lcyA9IGxlbmd0aCh1bmlxdWUoVmFjVWxpLnRvdCRzaXRlX2FsdF9pZCkpDQogIA0KICAjIHN1YnNldCBvZiB2YWx1ZXMgZm9yIHByZWRpY3Rpb24sIGZvciBlYWNoIHByZWRpY3Rvci4uLg0KICB4aGF0X2NvbXBldCA9IHNlcShmcm9tID0gbWluKFZhY1VsaS50b3QkY29tcGV0QyksIHRvID0gbWF4KFZhY1VsaS50b3QkY29tcGV0QyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3NyaSA9IHNlcShmcm9tID0gbWluKFZhY1VsaS50b3Qkc3JpQyksIHRvID0gbWF4KFZhY1VsaS50b3Qkc3JpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RyaSA9IHNlcShmcm9tID0gbWluKFZhY1VsaS50b3QkdHJpQyksIHRvID0gbWF4KFZhY1VsaS50b3QkdHJpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3R3aSA9IHNlcShmcm9tID0gbWluKFZhY1VsaS50b3QkdHdpQyksIHRvID0gbWF4KFZhY1VsaS50b3QkdHdpQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBqamEgPSBzZXEoZnJvbSA9IG1pbihWYWNVbGkudG90JHRlbXBqamFfdHNfMzBDKSwgdG8gPSBtYXgoVmFjVWxpLnRvdCR0ZW1wamphX3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3ByZWNpcGpqYSA9IHNlcShmcm9tID0gbWluKFZhY1VsaS50b3QkcHJlY2lwamphX3RzXzMwQyksIHRvID0gbWF4KFZhY1VsaS50b3QkcHJlY2lwamphX3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICB4aGF0X3RlbXBjb250ID0gc2VxKGZyb20gPSBtaW4oVmFjVWxpLnRvdCR0ZW1wY29udF90c18zMEMpLCB0byA9IG1heChWYWNVbGkudG90JHRlbXBjb250X3RzXzMwQyksIGxlbmd0aC5vdXQgPSAxMDApLA0KICBOeGhhdCA9IDEwMCwNCiAgDQogICMgLi4uIGFuZCBmb3IgcHJlZGljdGluZyBhdCBoaWdoL2xvdyB0ZW1wZXJhdHVyZSBsZXZlbHMNCiAgeGhhdF90ZW1wamphMiA9IGFzLm51bWVyaWMoYyhxdWFudGlsZShWYWNVbGkudG90JHRlbXBqamFfdHNfMzBDLDAuMDUpLHF1YW50aWxlKFZhY1VsaS50b3QkdGVtcGpqYV90c18zMEMsMC45NSkpKSwgDQogIE54aGF0MiA9IDINCikNCnN0cihzaHJ1Yl9ncmFkaWVudF9qYWdzLlZhY1VsaS5kYXRhKQ0KDQoNCmBgYA0KDQojIyMgPiBzcGVjaWZ5aW5nIG1vZGVsDQpgYGB7cn0NCndyaXRlKCINCiAgDQogIG1vZGVsew0KICAgIA0KICAgICMgcHJpb3JzDQogICAgICANCiAgICAgIGludGVyY2VwdCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIA0KICAgICAgYi5jb21wZXQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnNyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudHJpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50d2kgfiBkbm9ybSgwLCAwLjAwMDEpDQoNCiAgICAgIHNpZ21hLnBsb3Rncm91cCB+IGR1bmlmKDAsMTAwKQ0KICAgICAgdGF1LnBsb3Rncm91cCA8LSAxLyhzaWdtYS5wbG90Z3JvdXAgKiBzaWdtYS5wbG90Z3JvdXApDQogICAgICANCiAgICAgIGIudGVtcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi5wcmVjaXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgcGhpIH4gZGdhbW1hKDAuMSwgMC4xKQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGRpc2NyZXRlIHBhcnQNCg0KICAgICAgZm9yIChpIGluIDE6Tl9kaXNjcmV0ZSl7IA0KICAgICAgICBjb3YuZGlzW2ldIH4gZGJlcm4obXVbaV0pDQogICAgICAgIGxvZ2l0KG11W2ldKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuZGlzW2ldXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHdpICogdHdpLmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuZGlzW2ldICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmRpc1tpXQ0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGNvbnRpbnVvdXMgcGFydA0KDQogICAgICBmb3IgKGogaW4gMTpOX2NvbnQpew0KICAgICAgICBjb3YuY29udFtqXSB+IGRiZXRhKHBbal0sIHFbal0pDQogICAgICAgIHBbal0gPC0gbXUyW2pdICogcGhpDQogICAgICAgIHFbal0gPC0gKDEgLSBtdTJbal0pICogcGhpDQogICAgICAgIGxvZ2l0KG11MltqXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmNvbnRbal1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54MiAqICh0ZW1wY29udC50b3Rba11eMikgKw0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54ICogcHJlY2lwamphLnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpIA0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAgICMgYWRkIHByZWRpY3RlZCB2YWx1ZXMgKGRlcml2ZWQgcGFyYW1ldGVycykNCiAgICAgIGZvciAobSBpbiAxOk54aGF0KXsNCiAgICAgICAgcGhhdF9jb21wZXRbbV0gPC0gaW50ZXJjZXB0ICsgYi5jb21wZXQgKiB4aGF0X2NvbXBldFttXQ0KICAgICAgICBwaGF0X3NyaVttXSA8LSBpbnRlcmNlcHQgKyBiLnNyaSAqIHhoYXRfc3JpW21dDQogICAgICAgIHBoYXRfdHJpW21dIDwtIGludGVyY2VwdCArIGIudHJpICogeGhhdF90cmlbbV0NCiAgICAgICAgcGhhdF90d2lbbV0gPC0gaW50ZXJjZXB0ICsgYi50d2kgKiB4aGF0X3R3aVttXQ0KICAgICAgICBwaGF0X3RlbXBqamFbbV0gPC0gaW50ZXJjZXB0ICsgYi50ZW1wamphLnggKiB4aGF0X3RlbXBqamFbbV0gKyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphW21dXjIpDQogICAgICAgIHBoYXRfdGVtcGNvbnRbbV0gPC0gaW50ZXJjZXB0ICsgYi50ZW1wY29udC54ICogeGhhdF90ZW1wY29udFttXSArIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyBiLnByZWNpcGpqYS54ICogeGhhdF9wcmVjaXBqamFbbV0gKyBiLnByZWNpcGpqYS54MiAqICh4aGF0X3ByZWNpcGpqYVttXV4yKQ0KICAgICAgfQ0KDQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpKQ0KYGBgDQoNClNwZWNpZnkgdGhlIHBhcmFtZXRlcnMgdG8gYmUgbW9uaXRvcmVkOg0KYGBge3J9DQpwYXJhbXMgPC0gYygiaW50ZXJjZXB0IiwNCiAgICAgICAgICAgICJiLnRlbXBqamEueCIsICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgImIudGVtcGNvbnQueCIsICJiLnRlbXBjb250LngyIiwNCiAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgImIucHJlY2lwamphLngyIiwNCiAgICAgICAgICAgICJiLmNvbXBldCIsIA0KICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICJiLnRyaSIsDQogICAgICAgICAgICAiYi50d2kiLA0KICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAic2lnbWEucGxvdGdyb3VwIiwNCiAgICAgICAgICAgICJwaGkiLA0KICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdHdpIiwgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIikNCmBgYA0KDQojIyMgPiBydW4gJiBldmFsdWF0ZSBtb2RlbA0KPGJyPg0KDQojIyMgKkJldHVsYSBuYW5hKg0KYGBge3J9DQojIHJ1biBtb2RlbA0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbiA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuQmV0TmFuLmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHMiLCAic2hydWJfZ3JhZGllbnQuc3BlYy5qYWdzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY2hhaW5zID0gMywgICAgICAgICAgICAgICAgICAgICAgICMgbm8uIE1hcmtvdiBjaGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLml0ZXIgPSAxMDAwMDAsIG4uYnVybmluID0gNzAwMDAsICAjIG5vLiBpdGVyYXRpb25zICYgYnVybi1pbiBmcmFjdGlvbiBwZXIgY2hhaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnRoaW4gPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaW5uaW5nIHJhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESUMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAjIGRvIG5vdCBjb21wdXRlIGRldmlhbmNlLCBwRCwgYW5kIERJQw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcuZGlyZWN0b3J5ID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MuYmFyID0gInRleHQiKSANCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4pICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuQmV0TmFuIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4kQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbiksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5CZXROYW4gPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4kQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuQmV0TmFuW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLkJldE5hbltwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbiA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4gJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuQmV0TmFuLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQooZWZmZWN0X3NpemVfcGxvdC5CZXROYW4gPC0gbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbiwgdGl0bGVfc3RyaW5nID0gIkJldHVsYSBuYW5hIiwgcGxvdF93aWR0aCA9IDExKSkNCmBgYA0KDQoqICoqdW5pbW9kYWwgcmVzcG9uc2UgdG8gdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgKHNpZykqKg0KKiBzbGlnaHRseSBuZWdhdGl2ZSByZXNwb25zZSB0byBjb21wZXRpdGlvbiAmIHByZWNpcGl0YXRpb24gKGxpbmVhcikgKG4ucy4pDQoNCjxicj4NCg0KQXMgdGhlIHF1YWRyYXRpYyB0ZXJtcyBmb3Igc3VtbWVyIHRlbXBlcmF0dXJlIGFuZCBwcmVjaXBpdGF0aW9uIHdlcmUgbm90IHNpZ25pZmljYW50LCB0aGV5IHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBtb2RlbCBiZWZvcmUgcmUtcnVubmluZzoNCmBgYHtyfQ0KIyBuZXcgbW9kZWwgb2JqZWN0IHdpdGggdGVybXMgcmVtb3ZlZA0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQogICAgDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmNvbXBldCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc3JpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50cmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnR3aSB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBjb250LnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgcGhpIH4gZGdhbW1hKDAuMSwgMC4xKQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGRpc2NyZXRlIHBhcnQNCg0KICAgICAgZm9yIChpIGluIDE6Tl9kaXNjcmV0ZSl7IA0KICAgICAgICBjb3YuZGlzW2ldIH4gZGJlcm4obXVbaV0pDQogICAgICAgIGxvZ2l0KG11W2ldKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuZGlzW2ldXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHdpICogdHdpLmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuZGlzW2ldICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmRpc1tpXQ0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGNvbnRpbnVvdXMgcGFydA0KDQogICAgICBmb3IgKGogaW4gMTpOX2NvbnQpew0KICAgICAgICBjb3YuY29udFtqXSB+IGRiZXRhKHBbal0sIHFbal0pDQogICAgICAgIHBbal0gPC0gbXUyW2pdICogcGhpDQogICAgICAgIHFbal0gPC0gKDEgLSBtdTJbal0pICogcGhpDQogICAgICAgIGxvZ2l0KG11MltqXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmNvbnRbal1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHRlbXBqamEudG90W2tdXjIpICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHRlbXBjb250LnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LngyICogKHRlbXBjb250LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiBwcmVjaXBqamEudG90W2tdICMgKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgIyBhZGQgcHJlZGljdGVkIHZhbHVlcyAoZGVyaXZlZCBwYXJhbWV0ZXJzKQ0KICAgICAgZm9yIChtIGluIDE6TnhoYXQpew0KICAgICAgICBwaGF0X2NvbXBldFttXSA8LSBpbnRlcmNlcHQgKyBiLmNvbXBldCAqIHhoYXRfY29tcGV0W21dDQogICAgICAgIHBoYXRfc3JpW21dIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogeGhhdF90cmlbbV0NCiAgICAgICAgcGhhdF90d2lbbV0gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnR3aSAqIHhoYXRfdHdpW21dDQogICAgICAgIHBoYXRfdGVtcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSAjICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphW21dXjIpDQogICAgICAgIHBoYXRfdGVtcGNvbnRbbV0gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYi50ZW1wY29udC54ICogeGhhdF90ZW1wY29udFttXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiB4aGF0X3ByZWNpcGpqYVttXSAjICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcGNvbnRYdGVtcFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LngyICogKHhoYXRfdGVtcGNvbnRbbV1eMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYTJbcF0gIyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHhoYXRfdGVtcGpqYTJbcF1eMikNCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIA0KICAgICAgfQ0KICAiLCBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5CZXROYW4yLmphZ3MiKSkNCg0KIyBzcGVjaWZ5IG5ldyBzZXQgb2YgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQNCnBhcmFtc19CZXROYW4yIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgICJiLnRlbXBqamEueCIsICMgImIudGVtcGpqYS54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnRlbXBjb250LngiLCAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHdpIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdHdpIiwgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIiwgInBoYXRfdGVtcGNvbnRYdGVtcCIpDQoNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5CZXROYW4uZGF0YSwgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX0JldE5hbjIsICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LkJldE5hbjIuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbjIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbjIkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuQmV0TmFuMiA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbjIkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuQmV0TmFuMltwYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkJldE5hbjIkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuQmV0TmFuMltwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LkJldE5hbjIgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuQmV0TmFuMiwgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0KIyBlZmZlY3Qgc2l6ZSBwbG90DQooZWZmZWN0X3NpemVfcGxvdC5CZXROYW4yIDwtIG1vZGVsX3Bsb3RfbWFyZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yLCB0aXRsZV9zdHJpbmcgPSAiQmV0dWxhIG5hbmEiLCBwbG90X3dpZHRoID0gOC41KSkNCg0KYGBgDQoNCiogKnVuaW1vZGFsIHJlc3BvbnNlIHRvIHRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5IChtLnMuKSoNCiogc2xpZ2h0bHkgbmVnYXRpdmUgcmVzcG9uc2UgdG8gY29tcGV0aXRpb24gJiBwcmVjaXBpdGF0aW9uIChsaW5lYXIpIChuLnMuKQ0KDQo8YnI+DQoNCg0KIyMjICpDYXNzaW9wZSB0ZXRyYWdvbmEqDQpgYGB7cn0NCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLkNhc1RldC5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuQ2FzVGV0IDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LkNhc1RldCksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5DYXNUZXQgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuQ2FzVGV0W3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQ2FzVGV0JEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLkNhc1RldFtwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQ2FzVGV0JEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LkNhc1RldCA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5DYXNUZXQgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuQ2FzVGV0LCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQojIChlZmZlY3Rfc2l6ZV9wbG90LkNhc1RldCA8LSBtb2RlbF9wbG90X2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkNhc1RldCkpDQpgYGANCg0KKiAqKm5vdCBjb252ZXJnaW5nKio6IHJlYWxseSBsYXJnZSBSLWhhdCB2YWx1ZXMgKG9ubHkgMTYgbm9uLXplcm8gdmFsdWVzKQ0KPGJyPg0KDQojIyMgKkVtcGV0cnVtIG5pZ3J1bSoNCmBgYHtyfQ0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZyA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuRW1wTmlnLmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHMiLCAic2hydWJfZ3JhZGllbnQuc3BlYy5qYWdzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY2hhaW5zID0gMywgICAgICAgICAgICAgICAgICAgICAgICMgbm8uIE1hcmtvdiBjaGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLml0ZXIgPSAxMDAwMDAsIG4uYnVybmluID0gNzAwMDAsICAjIG5vLiBpdGVyYXRpb25zICYgYnVybi1pbiBmcmFjdGlvbiBwZXIgY2hhaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnRoaW4gPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaW5uaW5nIHJhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESUMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAjIGRvIG5vdCBjb21wdXRlIGRldmlhbmNlLCBwRCwgYW5kIERJQw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcuZGlyZWN0b3J5ID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MuYmFyID0gInRleHQiKQ0KDQojIHBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZykgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZyRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuRW1wTmlnKSwiW1tdIixmaXhlZD1GQUxTRSksICJbIiwgMSkpKSAjJT4lIHByaW50DQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLkVtcE5pZyA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZyRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5FbXBOaWdbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWckQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuRW1wTmlnW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWckQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuRW1wTmlnIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LkVtcE5pZyAlPiUgDQogIGxlZnRfam9pbihjaV85MC5FbXBOaWcsIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCiMgZWZmZWN0IHNpemUgcGxvdA0KKGVmZmVjdF9zaXplX3Bsb3QuRW1wTmlnIDwtIG1vZGVsX3Bsb3Rfc2lnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkVtcE5pZywgdGl0bGVfc3RyaW5nID0gIkVtcGV0cnVtIG5pZ3J1bSIsIHBsb3Rfd2lkdGggPSAxMSkpDQoNCmBgYA0KDQoqICoqcG9zaXRpdmUgcmVzcG9uc2UgdG8gcHJlY2lwaXRhdGlvbiAobGluZWFyLCBzaWcuKSoqDQoqICp1bmltb2RhbCByZXNwb25zZSB0byB0ZW1wZXJhdHVyZSAobS5zLikqDQoqIHNsaWdodGx5IHBvc2l0aXZlIHJlc3BvbnNlIHRvIGNvbXBldGl0aW9uLCBTUkkgYW5kIFRXSSAobi5zLikNCjxicj4NCg0KQXMgdGhlIHF1YWRyYXRpYyB0ZXJtcyBmb3IgdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgYW5kIHByZWNpcGl0YXRpb24gd2VyZSBub3Qgc2lnbmlmaWNhbnQsIHRoZXkgd2VyZSByZW1vdmVkIGZyb20gdGhlIG1vZGVsIGJlZm9yZSByZS1ydW5uaW5nOg0KYGBge3J9DQojIG5ldyBtb2RlbCBvYmplY3Qgd2l0aCB0ZXJtcyByZW1vdmVkDQp3cml0ZSgiDQogIA0KICBtb2RlbHsNCiAgICANCiAgICAjIHByaW9ycw0KICAgICAgDQogICAgICBpbnRlcmNlcHQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICANCiAgICAgIGIuY29tcGV0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi5zcmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnRyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudHdpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KDQogICAgICBzaWdtYS5wbG90Z3JvdXAgfiBkdW5pZigwLDEwMCkNCiAgICAgIHRhdS5wbG90Z3JvdXAgPC0gMS8oc2lnbWEucGxvdGdyb3VwICogc2lnbWEucGxvdGdyb3VwKQ0KICAgICAgDQogICAgICBiLnRlbXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBjb250LnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi50ZW1wY29udC54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi5wcmVjaXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnByZWNpcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgDQogICAgICBwaGkgfiBkZ2FtbWEoMC4xLCAwLjEpDQogICAgICANCiAgICAgIA0KICAgICMgTElLRUxJSE9PRCBmb3IgZGlzY3JldGUgcGFydA0KDQogICAgICBmb3IgKGkgaW4gMTpOX2Rpc2NyZXRlKXsgDQogICAgICAgIGNvdi5kaXNbaV0gfiBkYmVybihtdVtpXSkNCiAgICAgICAgbG9naXQobXVbaV0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5kaXNbaV1dICsgI0FCIGFkZGVkIHRoaXMsIH49IHJhbmRvbSBlZmZlY3Qgb2YgcGxvdCBncm91cA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5jb21wZXQgKiBjb21wZXQuZGlzW2ldICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnR3aSAqIHR3aS5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLmRpc1tpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5kaXNbaV0NCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBjb250aW51b3VzIHBhcnQNCg0KICAgICAgZm9yIChqIGluIDE6Tl9jb250KXsNCiAgICAgICAgY292LmNvbnRbal0gfiBkYmV0YShwW2pdLCBxW2pdKQ0KICAgICAgICBwW2pdIDwtIG11MltqXSAqIHBoaQ0KICAgICAgICBxW2pdIDwtICgxIC0gbXUyW2pdKSAqIHBoaQ0KICAgICAgICBsb2dpdChtdTJbal0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5jb250W2pdXSArICNBQiBhZGRlZCB0aGlzLCB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBjb250LngyICogKHRlbXBjb250LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiBwcmVjaXBqamEudG90W2tdICMgKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgIyBhZGQgcHJlZGljdGVkIHZhbHVlcyAoZGVyaXZlZCBwYXJhbWV0ZXJzKQ0KICAgICAgZm9yIChtIGluIDE6TnhoYXQpew0KICAgICAgICBwaGF0X2NvbXBldFttXSA8LSBpbnRlcmNlcHQgKyBiLmNvbXBldCAqIHhoYXRfY29tcGV0W21dDQogICAgICAgIHBoYXRfc3JpW21dIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogeGhhdF90cmlbbV0NCiAgICAgICAgcGhhdF90d2lbbV0gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnR3aSAqIHhoYXRfdHdpW21dDQogICAgICAgIHBoYXRfdGVtcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamFbbV1eMikNCiAgICAgICAgcGhhdF90ZW1wY29udFttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB4aGF0X3RlbXBjb250W21dICMgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiB4aGF0X3ByZWNpcGpqYVttXSAjICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcGNvbnRYdGVtcFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphMltwXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamEyW3BdXjIpDQogICAgICAgIH0NCiAgICAgIH0NCg0KICAgIA0KICAgICAgfQ0KICAiLCBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5FbXBOaWcyLmphZ3MiKSkNCg0KIyBzcGVjaWZ5IG5ldyBzZXQgb2YgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQNCnBhcmFtc19FbXBOaWcyIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgICJiLnRlbXBqamEueCIsICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHdpIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdHdpIiwgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIiwgInBoYXRfdGVtcGNvbnRYdGVtcCIpDQoNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5FbXBOaWcuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc19FbXBOaWcyLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LkVtcE5pZzIuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LkVtcE5pZzIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZzIkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuRW1wTmlnMiA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LkVtcE5pZyRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5FbXBOaWcyW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuRW1wTmlnMiRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5FbXBOaWcyW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5FbXBOaWcyJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LkVtcE5pZzIgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuRW1wTmlnMiAlPiUgDQogIGxlZnRfam9pbihjaV85MC5FbXBOaWcyLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQojIGVmZmVjdCBzaXplIHBsb3QNCihlZmZlY3Rfc2l6ZV9wbG90LkVtcE5pZzIgPC0gbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LkVtcE5pZzIsIHRpdGxlX3N0cmluZyA9ICJFbXBldHJ1bSBuaWdydW0iLCBwbG90X3dpZHRoID0gOC41KSkNCg0KYGBgDQoNCiogKip1bmltb2RhbCByZXNwb25zZSB0byB0ZW1wZXJhdHVyZSwgcG9zaXRpdmUgcmVzcG9uc2UgdG8gcHJlY2lwaXRhdGlvbiAobGluZWFyKSAoc2lnLikqKiwgKm5lZ2F0aXZlIHJlc3BvbnNlIHRvIHRlbXAuIHZhcmlhYmlsaXR5IChtLnMuKSoNCiogcG9zaXRpdmUgcmVzcG9uc2UgdG8gY29tcGV0aXRpb24sIFRXSSAobi5zLikNCg0KPGJyPg0KDQojIyMgKlBoeWxsb2RvY2UgY2FlcnVsZWEqDQpgYGB7cn0NCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLlBoeUNhZS5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuUGh5Q2FlIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlBoeUNhZSksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5QaHlDYWUgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuUGh5Q2FlW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUGh5Q2FlJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlBoeUNhZVtwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUGh5Q2FlJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlBoeUNhZSA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5QaHlDYWUgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuUGh5Q2FlLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQpgYGANCg0KKiAqKm5vdCBjb252ZXJnZWQqKiAob25seSAxMCBub24temVybyB2YWx1ZXMpDQo8YnI+DQoNCiMjIyAqUmhvZG9kZW5kcm9uIGdyb2VubGFuZGljdW0qDQpgYGB7cn0NCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8gPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLlJob0dyby5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8pICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvR3JvIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8kQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlJob0dybyksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5SaG9Hcm8gPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8kQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuUmhvR3JvW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlJob0dyb1twYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlJob0dybyA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8gJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuUmhvR3JvLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQojIGVmZmVjdCBzaXplIHBsb3QNCihlZmZlY3Rfc2l6ZV9wbG90LlJob0dybyA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8sIHRpdGxlX3N0cmluZyA9ICJSaG9kb2RlbmRyb24gZ3JvZW5sYW5kaWN1bSIsIHBsb3Rfd2lkdGggPSAxMSkpDQoNCmBgYA0KDQoqICoqdW5pbW9kYWwgcmVzcG9uc2UgdG8gdGVtcGVyYXR1cmUgJiBsaW5lYXIgdG8gcHJlY2lwaXRhdGlvbiAoc2lnLikqKiANCiogc2xpZ2h0bHkgcG9zaXRpdmUgcmVzcG9uc2UgdG8gU1JJLCB0ZW1wLiB2YXJpYXRpb24gKG4ucy4pDQoqIHNsaWdodGx5IG5lZ2F0aXZlIHJlc3BvbnN0IHRvIFRXSSAobi5zLikNCiogbGFyZ2UgdmFyaWF0aW9uIGluIGNvbXBldGl0b24gcmVzcG9uc2UgYXMgdGhlcmUgd2FzIG9ubHkgb25lIChob3dldmVyIHJhcmUpIHRhbGxlci1ncm93aW5nIHNwZWNpZXMgaW4gdGhlIHN5c3RlbSAoKlIuIHRvbWVudG9zdW0qKQ0KDQo8YnI+DQoNCkFzIHRoZSBxdWFkcmF0aWMgdGVybXMgZm9yIHRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5IGFuZCBwcmVjaXBpdGF0aW9uIHdlcmUgbm90IHNpZ25pZmljYW50LCB0aGV5IHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBtb2RlbCBiZWZvcmUgcmUtcnVubmluZzoNCmBgYHtyfQ0KIyBuZXcgbW9kZWwgb2JqZWN0IHdpdGggdGVybXMgcmVtb3ZlZA0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQogICAgDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmNvbXBldCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc3JpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50cmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnR3aSB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcGNvbnQueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgcGhpIH4gZGdhbW1hKDAuMSwgMC4xKQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGRpc2NyZXRlIHBhcnQNCg0KICAgICAgZm9yIChpIGluIDE6Tl9kaXNjcmV0ZSl7IA0KICAgICAgICBjb3YuZGlzW2ldIH4gZGJlcm4obXVbaV0pDQogICAgICAgIGxvZ2l0KG11W2ldKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuZGlzW2ldXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHdpICogdHdpLmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuZGlzW2ldICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmRpc1tpXQ0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGNvbnRpbnVvdXMgcGFydA0KDQogICAgICBmb3IgKGogaW4gMTpOX2NvbnQpew0KICAgICAgICBjb3YuY29udFtqXSB+IGRiZXRhKHBbal0sIHFbal0pDQogICAgICAgIHBbal0gPC0gbXUyW2pdICogcGhpDQogICAgICAgIHFbal0gPC0gKDEgLSBtdTJbal0pICogcGhpDQogICAgICAgIGxvZ2l0KG11MltqXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmNvbnRbal1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBjb250LngyICogKHRlbXBjb250LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiBwcmVjaXBqamEudG90W2tdICMgKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgIyBhZGQgcHJlZGljdGVkIHZhbHVlcyAoZGVyaXZlZCBwYXJhbWV0ZXJzKQ0KICAgICAgZm9yIChtIGluIDE6TnhoYXQpew0KICAgICAgICBwaGF0X2NvbXBldFttXSA8LSBpbnRlcmNlcHQgKyBiLmNvbXBldCAqIHhoYXRfY29tcGV0W21dDQogICAgICAgIHBoYXRfc3JpW21dIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogeGhhdF90cmlbbV0NCiAgICAgICAgcGhhdF90d2lbbV0gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnR3aSAqIHhoYXRfdHdpW21dDQogICAgICAgIHBoYXRfdGVtcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamFbbV1eMikNCiAgICAgICAgcGhhdF90ZW1wY29udFttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB4aGF0X3RlbXBjb250W21dICMgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiB4aGF0X3ByZWNpcGpqYVttXSAjICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcGNvbnRYdGVtcFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphMltwXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamEyW3BdXjIpDQogICAgICAgIH0NCiAgICAgIH0NCg0KICAgIA0KICAgICAgfQ0KICAiLCBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yLmphZ3MiKSkNCg0KIyBzcGVjaWZ5IG5ldyBzZXQgb2YgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQNCnBhcmFtc19SaG9Hcm8yIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgICJiLnRlbXBqamEueCIsICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHdpIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdHdpIiwgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIiwgInBoYXRfdGVtcGNvbnRYdGVtcCIpDQoNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5SaG9Hcm8uZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc19SaG9Hcm8yLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LlJob0dybzIuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LlJob0dybzIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybzIkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlJob0dybyksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5SaG9Hcm8yIDwtIGRhdGEuZnJhbWUocTUgPSBOQSwgcTk1ID0gTkEsIHBhcmFtID0gTkEpDQpmb3IgKHBhcmFtIGluIDE6KGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuUmhvR3JvJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLlJob0dybzJbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlJob0dybzJbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob0dybzIkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvR3JvMiA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLlJob0dybzIsIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCiMgZWZmZWN0IHNpemUgcGxvdA0KKGVmZmVjdF9zaXplX3Bsb3QuUmhvR3JvMiA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Hcm8yLCB0aXRsZV9zdHJpbmcgPSAiUmhvZG9kZW5kcm9uIGdyb2VubGFuZGljdW0iLCBwbG90X3dpZHRoID0gOC41KSkNCg0KYGBgDQoNCiogKip1bmltb2RhbCByZXNwb25zZSB0byB0ZW1wZXJhdHVyZSBhbmQgbmVnYXRpdmUgcmVzcG9uc2UgdG8gcHJlY2lwaXRhdGlvbiAobGluZWFyKSwgcG9zaXRpdmUgcmVzcG9uc2UgdG8gdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgKHNpZy4pKioNCiogcG9zaXRpdmUgcmVzcG9uc2UgdG8gU1JJIChuLnMuKQ0KKiBsYXJnZSB2YXJpYXRpb24gaW4gY29tcGV0aXRvbiByZXNwb25zZSBhcyB0aGVyZSB3YXMgb25seSBvbmUgKGhvd2V2ZXIgcmFyZSkgdGFsbGVyLWdyb3dpbmcgc3BlY2llcyBpbiB0aGUgc3lzdGVtICgqUi4gdG9tZW50b3N1bSopDQoNCjxicj4NCg0KIyMjICpSaG9kb2RlbmRyb24gdG9tZW50b3N1bSoNCmBgYHtyfQ0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob1RvbSA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuUmhvVG9tLmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHMiLCAic2hydWJfZ3JhZGllbnQuc3BlYy5qYWdzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY2hhaW5zID0gMywgICAgICAgICAgICAgICAgICAgICAgICMgbm8uIE1hcmtvdiBjaGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLml0ZXIgPSAxMDAwMDAsIG4uYnVybmluID0gNzAwMDAsICAjIG5vLiBpdGVyYXRpb25zICYgYnVybi1pbiBmcmFjdGlvbiBwZXIgY2hhaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnRoaW4gPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaW5uaW5nIHJhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESUMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAjIGRvIG5vdCBjb21wdXRlIGRldmlhbmNlLCBwRCwgYW5kIERJQw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcuZGlyZWN0b3J5ID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MuYmFyID0gInRleHQiKQ0KDQojIHBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob1RvbSkgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5SaG9Ub20gPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob1RvbSRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvVG9tKSwiW1tdIixmaXhlZD1GQUxTRSksICJbIiwgMSkpKSAjJT4lIHByaW50DQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLlJob1RvbSA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlJob1RvbSRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5SaG9Ub21bcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Ub20kQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuUmhvVG9tW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5SaG9Ub20kQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuUmhvVG9tIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LlJob1RvbSAlPiUgDQogIGxlZnRfam9pbihjaV85MC5SaG9Ub20sIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCmBgYA0KDQoqICoqbm90IGNvbnZlcmdpbmcqKjogcmVsYXRpdmVseSBsYXJnZSBSLWhhdCB2YWx1ZXMsIGxhcmdlIHZhcmlhdGlvbiBpbiBwYXJhbWV0ZXIgZXN0aW1hdGVzIChvbmx5IDEzIG5vbi16ZXJvIHZhbHVlcykNCjxicj4NCg0KIyMjICpTYWxpeCBhcmN0b3BoaWxhKg0KYGBge3J9DQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsQXJjIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5TYWxBcmMuZGF0YSwgICAgIyBpbnB1dCBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgIyBKQUdTIHRvIGNyZWF0ZSBpbml0aWFsIHZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5zcGVjLmphZ3MiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5jaGFpbnMgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgIyBuby4gTWFya292IGNoYWlucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uaXRlciA9IDEwMDAwMCwgbi5idXJuaW4gPSA3MDAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsQXJjKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LlNhbEFyYyA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsQXJjJEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQogICMgbXV0YXRlKHBhcmFtID0gYXMudmVjdG9yKHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxBcmMpLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuU2FsQXJjIDwtIGRhdGEuZnJhbWUocTUgPSBOQSwgcTk1ID0gTkEsIHBhcmFtID0gTkEpDQpmb3IgKHBhcmFtIGluIDE6KGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsQXJjJEJVR1NvdXRwdXQkc2ltcy5saXN0KS00KSl7DQogIGNpXzkwLlNhbEFyY1twYXJhbSwxOjJdIDwtIHF1YW50aWxlKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEFyYyRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5TYWxBcmNbcGFyYW0sIDNdIDwtIG5hbWVzKGRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEFyYyRCVUdTb3V0cHV0JHNpbXMubGlzdCkpW3BhcmFtXQ0KfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxBcmMgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsQXJjICU+JSANCiAgbGVmdF9qb2luKGNpXzkwLlNhbEFyYywgYnkgPSAicGFyYW0iKSAlPiUgDQogICMgcmVvcmRlciBhbmQgcmVuYW1lIGNvbHMNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICBsOTAgPSBxNSwNCiAgICAgICAgIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAlPiUgcHJpbnQNCg0KYGBgDQoNCiogKipub3QgY29udmVyZ2luZyB3ZWxsKio6IHJlbGF0aXZlbHkgbGFyZ2UgUi1oYXQgdmFsdWVzLCBxdWl0ZSBzb21lIHZhcmlhdGlvbiBpbiBwYXJhbWV0ZXIgZXN0aW1hdGVzIChvbmx5IDEzIG5vbi16ZXJvIHZhbHVlcykNCjxicj4NCg0KIyMjICpTYWxpeCBnbGF1Y2EqDQpgYGB7cn0NCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEgPC0gamFncyhzaHJ1Yl9ncmFkaWVudF9qYWdzLlNhbEdsYS5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LnNwZWMuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEpICNjaGVjayBjb252ZXJnZW5jZSwgZXRjLg0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGV4dHJhY3QgY29lZmZpY2llbnRzIA0KY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhIDwtIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCiAgIyBtdXRhdGUocGFyYW0gPSBhcy52ZWN0b3Ioc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYSksIltbXSIsZml4ZWQ9RkFMU0UpLCAiWyIsIDEpKSkgIyU+JSBwcmludA0KDQojIGFkZCA5MCUgQ0lzDQpjaV85MC5TYWxHbGEgPC0gZGF0YS5mcmFtZShxNSA9IE5BLCBxOTUgPSBOQSwgcGFyYW0gPSBOQSkNCmZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEkQlVHU291dHB1dCRzaW1zLmxpc3QpLTQpKXsNCiAgY2lfOTAuU2FsR2xhW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhJEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQogIGNpXzkwLlNhbEdsYVtwYXJhbSwgM10gPC0gbmFtZXMoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYSA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEgJT4lIA0KICBsZWZ0X2pvaW4oY2lfOTAuU2FsR2xhLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQojIGVmZmVjdCBzaXplIHBsb3QNCihlZmZlY3Rfc2l6ZV9wbG90LlNhbEdsYSA8LSBtb2RlbF9wbG90X3NpZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEsIHRpdGxlX3N0cmluZyA9ICJTYWxpeCBnbGF1Y2EiLCBwbG90X3dpZHRoID0gMTEpKQ0KDQpgYGANCg0KKiAqKnBvc2l0aXZlIHJlc3BvbnNlIHRvIGNvbXBldGl0aW9uIChzaWcuKSoqDQoqIHNsaWdodGx5IG5lZ2F0aXZlIHJlc3BvbnNlIHRvIHRlbXBlcmF0dXJlICYgU1JJIChuLnMuKQ0KDQo8YnI+DQoNCkFzIHRoZSBxdWFkcmF0aWMgdGVybXMgZm9yIHN1bW1lciB0ZW1wZXJhdHVyZSwgdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgYW5kIHN1bW1lciBwcmVjaXBpdGF0aW9uIHdlcmUgbm90IHNpZ25pZmljYW50LCB0aGV5IHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBtb2RlbCBiZWZvcmUgcmUtcnVubmluZzoNCmBgYHtyfQ0KIyBuZXcgbW9kZWwgb2JqZWN0IHdpdGggdGVybXMgcmVtb3ZlZA0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQogICAgDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmNvbXBldCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc3JpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50cmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnR3aSB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcGNvbnQueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgcGhpIH4gZGdhbW1hKDAuMSwgMC4xKQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGRpc2NyZXRlIHBhcnQNCg0KICAgICAgZm9yIChpIGluIDE6Tl9kaXNjcmV0ZSl7IA0KICAgICAgICBjb3YuZGlzW2ldIH4gZGJlcm4obXVbaV0pDQogICAgICAgIGxvZ2l0KG11W2ldKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuZGlzW2ldXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHdpICogdHdpLmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuZGlzW2ldICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmRpc1tpXQ0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGNvbnRpbnVvdXMgcGFydA0KDQogICAgICBmb3IgKGogaW4gMTpOX2NvbnQpew0KICAgICAgICBjb3YuY29udFtqXSB+IGRiZXRhKHBbal0sIHFbal0pDQogICAgICAgIHBbal0gPC0gbXUyW2pdICogcGhpDQogICAgICAgIHFbal0gPC0gKDEgLSBtdTJbal0pICogcGhpDQogICAgICAgIGxvZ2l0KG11MltqXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmNvbnRbal1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHRlbXBqamEudG90W2tdXjIpICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHRlbXBjb250LnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAodGVtcGNvbnQudG90W2tdXjIpICsNCiAgICAgICAgICAgICAgICAgICAgYi5wcmVjaXBqamEueCAqIHByZWNpcGpqYS50b3Rba10gIyArIA0KICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHByZWNpcGpqYS50b3Rba11eMikNCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgICAjIGFkZCBwcmVkaWN0ZWQgdmFsdWVzIChkZXJpdmVkIHBhcmFtZXRlcnMpDQogICAgICBmb3IgKG0gaW4gMTpOeGhhdCl7DQogICAgICAgIHBoYXRfY29tcGV0W21dIDwtIGludGVyY2VwdCArIGIuY29tcGV0ICogeGhhdF9jb21wZXRbbV0NCiAgICAgICAgcGhhdF9zcmlbbV0gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnNyaSAqIHhoYXRfc3JpW21dDQogICAgICAgIHBoYXRfdHJpW21dIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi50cmkgKiB4aGF0X3RyaVttXQ0KICAgICAgICBwaGF0X3R3aVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHdpICogeGhhdF90d2lbbV0NCiAgICAgICAgcGhhdF90ZW1wamphW21dIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphW21dICMgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamFbbV1eMikNCiAgICAgICAgcGhhdF90ZW1wY29udFttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB4aGF0X3RlbXBjb250W21dICMgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiB4aGF0X3ByZWNpcGpqYVttXSAjICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcGNvbnRYdGVtcFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphMltwXSAjICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBqamEueDIgKiAoeGhhdF90ZW1wamphMltwXV4yKQ0KICAgICAgICB9DQogICAgICB9DQoNCiAgICANCiAgICAgIH0NCiAgIiwgZmlsZS5wYXRoKCIuLiIsICJtb2RlbHMiLCAic2hydWJfZ3JhZGllbnQuU2FsR2xhMi5qYWdzIikpDQoNCiMgc3BlY2lmeSBuZXcgc2V0IG9mIHBhcmFtZXRlcnMgdG8gYmUgbW9uaXRvcmVkDQpwYXJhbXNfU2FsR2xhMiA8LSBjKCJpbnRlcmNlcHQiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wamphLngiLCAjICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHdpIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdHdpIiwgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIiwgInBoYXRfdGVtcGNvbnRYdGVtcCIpDQoNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5TYWxHbGEuZGF0YSwgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX1NhbEdsYTIsICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LlNhbEdsYTIuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuU2FsR2xhMiA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYSRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5TYWxHbGEyW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMiRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5TYWxHbGEyW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhMiAlPiUgDQogIGxlZnRfam9pbihjaV85MC5TYWxHbGEyLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQojIGVmZmVjdCBzaXplIHBsb3QNCihlZmZlY3Rfc2l6ZV9wbG90LlNhbEdsYTIgPC0gbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIsIHRpdGxlX3N0cmluZyA9ICJTYWxpeCBnbGF1Y2EiLCBwbG90X3dpZHRoID0gOCkpDQoNCmBgYA0KDQoqICoqcG9zaXRpdmUgcmVzcG9uc2UgdG8gdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgKGxpbmVhcikgYW5kIGNvbXBldGl0aW9uIChzaWcuKSoqDQoqIHBvc2l0aXZlIHJlc3BvbnNlIHRvIFRSSSwgbmVnYXRpdmUgcmVzcG9uc2UgdG8gU1JJIChuLnMuKQ0KDQo8YnI+DQoNCg0KIyMjICpWYWNjaW5pdW0gdWxpZ2lub3N1bSoNCmBgYHtyfQ0KbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaSA8LSBqYWdzKHNocnViX2dyYWRpZW50X2phZ3MuVmFjVWxpLmRhdGEsICAgICMgaW5wdXQgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaXRzID0gTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICMgSkFHUyB0byBjcmVhdGUgaW5pdGlhbCB2YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBhcmFtZXRlcnMgdG8gYmUgc2F2ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5maWxlID0gZmlsZS5wYXRoKCIuLiIsICJtb2RlbHMiLCAic2hydWJfZ3JhZGllbnQuc3BlYy5qYWdzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY2hhaW5zID0gMywgICAgICAgICAgICAgICAgICAgICAgICMgbm8uIE1hcmtvdiBjaGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLml0ZXIgPSAxMDAwMDAsIG4uYnVybmluID0gNzAwMDAsICAjIG5vLiBpdGVyYXRpb25zICYgYnVybi1pbiBmcmFjdGlvbiBwZXIgY2hhaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLnRoaW4gPSAyLCAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoaW5uaW5nIHJhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBESUMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAjIGRvIG5vdCBjb21wdXRlIGRldmlhbmNlLCBwRCwgYW5kIERJQw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcuZGlyZWN0b3J5ID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3MuYmFyID0gInRleHQiKQ0KDQojIHBsb3QobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaSkgI2NoZWNrIGNvbnZlcmdlbmNlLCBldGMuDQpgYGANCg0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIHBsb3QgZWZmZWN0IHNpemVzOg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaSRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuVmFjVWxpKSwiW1tdIixmaXhlZD1GQUxTRSksICJbIiwgMSkpKSAjJT4lIHByaW50DQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLlZhY1VsaSA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaSRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5WYWNVbGlbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuVmFjVWxpW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuVmFjVWxpIDwtIGNvZWZmLnNocnViX2dyYWRpZW50LlZhY1VsaSAlPiUgDQogIGxlZnRfam9pbihjaV85MC5WYWNVbGksIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCiMgZWZmZWN0IHNpemUgcGxvdA0KKGVmZmVjdF9zaXplX3Bsb3QuVmFjVWxpIDwtIG1vZGVsX3Bsb3RfbWFyZ19mdW5jdGlvbihjb2VmZi5zaHJ1Yl9ncmFkaWVudC5WYWNVbGksIHRpdGxlX3N0cmluZyA9ICJWYWNjaW5pdW0gdWxpZ2lub3N1bSIsIHBsb3Rfd2lkdGggPSAxMSkpDQoNCmBgYA0KDQoqICoqdW5pbW9kYWwgcmVzcG9uc2UgdG8gdGVtcGVyYXR1cmUgKHNpZy4pKiosICpUV0ksIGNvbXBldGl0aW9uIChtLnMuKSoNCiogcG9zaXRpdmUgcmVzcG9uc2UgdG8gU1JJIChuLnMuKQ0KDQo8YnI+DQoNCkFzIHRoZSBxdWFkcmF0aWMgdGVybXMgZm9yIHRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5IGFuZCBwcmVjaXBpdGF0aW9uIHdlcmUgbm90IHNpZ25pZmljYW50LCB0aGV5IHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBtb2RlbCBiZWZvcmUgcmUtcnVubmluZzoNCmBgYHtyfQ0KIyBuZXcgbW9kZWwgb2JqZWN0IHdpdGggdGVybXMgcmVtb3ZlZA0Kd3JpdGUoIg0KICANCiAgbW9kZWx7DQogICAgDQogICAgIyBwcmlvcnMNCiAgICAgIA0KICAgICAgaW50ZXJjZXB0IH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgDQogICAgICBiLmNvbXBldCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIuc3JpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50cmkgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnR3aSB+IGRub3JtKDAsIDAuMDAwMSkNCg0KICAgICAgc2lnbWEucGxvdGdyb3VwIH4gZHVuaWYoMCwxMDApDQogICAgICB0YXUucGxvdGdyb3VwIDwtIDEvKHNpZ21hLnBsb3Rncm91cCAqIHNpZ21hLnBsb3Rncm91cCkNCiAgICAgIA0KICAgICAgYi50ZW1wamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGpqYS54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wY29udC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcGNvbnQueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIucHJlY2lwamphLnggfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgICMgYi5wcmVjaXBqamEueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIA0KICAgICAgcGhpIH4gZGdhbW1hKDAuMSwgMC4xKQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGRpc2NyZXRlIHBhcnQNCg0KICAgICAgZm9yIChpIGluIDE6Tl9kaXNjcmV0ZSl7IA0KICAgICAgICBjb3YuZGlzW2ldIH4gZGJlcm4obXVbaV0pDQogICAgICAgIGxvZ2l0KG11W2ldKSA8LSBiX3Bsb3Rncm91cFtwbG90Z3JvdXAuZGlzW2ldXSArICMgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHdpICogdHdpLmRpc1tpXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuZGlzW2ldICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogdHJpLmRpc1tpXQ0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAjIExJS0VMSUhPT0QgZm9yIGNvbnRpbnVvdXMgcGFydA0KDQogICAgICBmb3IgKGogaW4gMTpOX2NvbnQpew0KICAgICAgICBjb3YuY29udFtqXSB+IGRiZXRhKHBbal0sIHFbal0pDQogICAgICAgIHBbal0gPC0gbXUyW2pdICogcGhpDQogICAgICAgIHFbal0gPC0gKDEgLSBtdTJbal0pICogcGhpDQogICAgICAgIGxvZ2l0KG11MltqXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmNvbnRbal1dICsgIyB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuY29tcGV0ICogY29tcGV0LmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh0ZW1wamphLnRvdFtrXV4yKSArIA0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB0ZW1wY29udC50b3Rba10gKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnRlbXBjb250LngyICogKHRlbXBjb250LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiBwcmVjaXBqamEudG90W2tdICMgKyANCiAgICAgICAgICAgICAgICAgICAgIyBiLnByZWNpcGpqYS54MiAqIChwcmVjaXBqamEudG90W2tdXjIpDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgIyBhZGQgcHJlZGljdGVkIHZhbHVlcyAoZGVyaXZlZCBwYXJhbWV0ZXJzKQ0KICAgICAgZm9yIChtIGluIDE6TnhoYXQpew0KICAgICAgICBwaGF0X2NvbXBldFttXSA8LSBpbnRlcmNlcHQgKyBiLmNvbXBldCAqIHhoYXRfY29tcGV0W21dDQogICAgICAgIHBoYXRfc3JpW21dIDwtIGludGVyY2VwdCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiB4aGF0X3NyaVttXQ0KICAgICAgICBwaGF0X3RyaVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIudHJpICogeGhhdF90cmlbbV0NCiAgICAgICAgcGhhdF90d2lbbV0gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgICAgICBiLnR3aSAqIHhoYXRfdHdpW21dDQogICAgICAgIHBoYXRfdGVtcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHhoYXRfdGVtcGpqYVttXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamFbbV1eMikNCiAgICAgICAgcGhhdF90ZW1wY29udFttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiLnRlbXBjb250LnggKiB4aGF0X3RlbXBjb250W21dICMgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKQ0KICAgICAgICBwaGF0X3ByZWNpcGpqYVttXSA8LSBpbnRlcmNlcHQgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIucHJlY2lwamphLnggKiB4aGF0X3ByZWNpcGpqYVttXSAjICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHhoYXRfcHJlY2lwamphW21dXjIpDQogICAgICAgIA0KICAgICAgICBmb3IgKHAgaW4gMTpOeGhhdDIpew0KICAgICAgICAgIHBoYXRfdGVtcGNvbnRYdGVtcFttLHBdIDwtIGludGVyY2VwdCArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHhoYXRfdGVtcGNvbnRbbV0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAoeGhhdF90ZW1wY29udFttXV4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54ICogeGhhdF90ZW1wamphMltwXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIudGVtcGpqYS54MiAqICh4aGF0X3RlbXBqamEyW3BdXjIpDQogICAgICAgIH0NCiAgICAgIH0NCg0KICAgIA0KICAgICAgfQ0KICAiLCBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5WYWNVbGkyLmphZ3MiKSkNCg0KIyBzcGVjaWZ5IG5ldyBzZXQgb2YgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQNCnBhcmFtc19WYWNVbGkyIDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgICJiLnRlbXBqamEueCIsICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi5jb21wZXQiLCANCiAgICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHdpIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICJzaWdtYS5wbG90Z3JvdXAiLA0KICAgICAgICAgICAgICAgICAgICAicGhpIiwNCiAgICAgICAgICAgICAgICAgICAgInBoYXRfY29tcGV0IiwgInBoYXRfc3JpIiwgInBoYXRfdHJpIiwgInBoYXRfdHdpIiwgInBoYXRfdGVtcGpqYSIsICJwaGF0X3RlbXBjb250IiwgInBoYXRfcHJlY2lwamphIiwgInBoYXRfdGVtcGNvbnRYdGVtcCIpDQoNCm1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyIDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5WYWNVbGkuZGF0YSwgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX1ZhY1VsaTIsICAgICAgICAgICAgICAgICAgICAgIyBwYXJhbWV0ZXJzIHRvIGJlIHNhdmVkDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LlZhY1VsaTIuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAwLCBuLmJ1cm5pbiA9IDcwMDAwLCAgIyBuby4gaXRlcmF0aW9ucyAmIGJ1cm4taW4gZnJhY3Rpb24gcGVyIGNoYWluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi50aGluID0gMiwgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGlubmluZyByYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRElDID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgIyBkbyBub3QgY29tcHV0ZSBkZXZpYW5jZSwgcEQsIGFuZCBESUMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JraW5nLmRpcmVjdG9yeSA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzLmJhciA9ICJ0ZXh0IikNCg0KIyBwbG90KG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyKSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCmBgYA0KDQpFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgcGxvdCBlZmZlY3Qgc2l6ZXM6DQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LlZhY1VsaTIgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaTIkQlVHU291dHB1dCRzdW1tYXJ5ICU+JSANCiAgYXMuZGF0YS5mcmFtZSAlPiUgDQogIHNlbGVjdCgnbWVhbicsJ3NkJywnMi41JScsJzk3LjUlJywnUmhhdCcpICU+JSANCiMgYWRkIGlkZW50aWZ5aW5nIGluZm8gdG8gZGF0YSBmcmFtZQ0KICByb3duYW1lc190b19jb2x1bW4odmFyID0gInBhcmFtIikNCg0KIyBhZGQgOTAlIENJcw0KY2lfOTAuVmFjVWxpMiA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlZhY1VsaSRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5WYWNVbGkyW3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuVmFjVWxpMiRCVUdTb3V0cHV0JHNpbXMubGlzdFtwYXJhbV0pWywxXSwgcHJvYnMgPSBjKDAuMDUsIDAuOTUpKQ0KICBjaV85MC5WYWNVbGkyW3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5WYWNVbGkyJEJVR1NvdXRwdXQkc2ltcy5saXN0KSlbcGFyYW1dDQp9DQoNCiMgam9pbiB0byBjb2VmZmljaWVudHMgdGFibGUNCmNvZWZmLnNocnViX2dyYWRpZW50LlZhY1VsaTIgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuVmFjVWxpMiAlPiUgDQogIGxlZnRfam9pbihjaV85MC5WYWNVbGkyLCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgIGw5MCA9IHE1LA0KICAgICAgICAgdTkwID0gcTk1LA0KICAgICAgICAgdTk1ID0gIjk3LjUlIiwNCiAgICAgICAgIFJoYXQpICU+JSBwcmludA0KDQojIGVmZmVjdCBzaXplIHBsb3QNCihlZmZlY3Rfc2l6ZV9wbG90LlZhY1VsaTIgPC0gbW9kZWxfcGxvdF9tYXJnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LlZhY1VsaTIsIHRpdGxlX3N0cmluZyA9ICJWYWNjaW5pdW0gdWxpZ2lub3N1bSIsIHBsb3Rfd2lkdGggPSA4LjUpKQ0KDQpgYGANCg0KKiAqKnVuaW1vZGFsIHJlc3BvbnNlIHRvIHRlbXBlcmF0dXJlIChzaWcuKSoqLCAqVFdJIChtLnMuKSoNCiogbmVnYXRpdmUgcmVzcG9uc2UgdG8gY29tcGV0aXRpb24sIHBvc2l0aXZlIHJlc3BvbnNlIHRvIFNSSSAobi5zLikNCg0KPGJyPg0KDQojIyMgPiBjb21iaW5lIGFsbCBwbG90cyANCmBgYHtyLCBldmFsID0gRkFMU0V9DQojIDN4MiBncmlkICh2ZXJ0aWNhbCBsYXlvdXQpDQoobnV1a19lZmZlY3RzaXplX3Bsb3RfZ3JpZF92ZXIgPC0gcGxvdF9ncmlkKGVmZmVjdF9zaXplX3Bsb3QuQmV0TmFuLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5FbXBOaWcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3Rfc2l6ZV9wbG90LlJob0dybywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdF9zaXplX3Bsb3QuU2FsR2xhLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5WYWNVbGksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImEpIiwgImIpIiwgImMpIiwgImQpIiwgImUpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAyMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfZm9udGZhY2UgPSAicGxhaW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IC0yLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikpDQoNCiMgc2F2ZSBwbG90DQojIHNhdmVfcGxvdChmaWxlLnBhdGgoIi4uIiwgImZpZ3VyZXMiLCAibnV1a19zaHJ1Yl9kcml2ZXJzX2JldGFiaW5vbV9lZmZlY3Rfc2l6ZV9wYW5lbHNfdmVydC5lcHMiKSwNCiMgICAgICAgICAgIG51dWtfZWZmZWN0c2l6ZV9wbG90X2dyaWRfdmVyLCBiYXNlX2hlaWdodCA9IDE1LCBiYXNlX2FzcGVjdF9yYXRpbyA9IDAuOCkNCg0KIyAzeDIgZ3JpZCByZWR1Y2VkIHByZWRpY3RvciB0ZXJtcw0KKG51dWtfcmVkdWNlZF9lZmZlY3RzaXplX3Bsb3RfZ3JpZF92ZXIgPC0gcGxvdF9ncmlkKGVmZmVjdF9zaXplX3Bsb3QuQmV0TmFuMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdF9zaXplX3Bsb3QuRW1wTmlnMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdF9zaXplX3Bsb3QuUmhvR3JvMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdF9zaXplX3Bsb3QuU2FsR2xhMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdF9zaXplX3Bsb3QuVmFjVWxpMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiYSkiLCAiYikiLCAiYykiLCAiZCkiLCAiZSkiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDIwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9mb250ZmFjZSA9ICJwbGFpbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gLTIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKSkNCg0KIyBzYXZlIHBsb3QNCiMgc2F2ZV9wbG90KGZpbGUucGF0aCgiLi4iLCAiZmlndXJlcyIsICJudXVrX3NocnViX2RyaXZlcnNfYmV0YWJpbm9tX3JlZHVjZWRfZWZmZWN0X3NpemVfcGFuZWxzX3ZlcnQuZXBzIiksDQojICAgICAgICAgICBudXVrX3JlZHVjZWRfZWZmZWN0c2l6ZV9wbG90X2dyaWRfdmVyLCBiYXNlX2hlaWdodCA9IDE1LCBiYXNlX2FzcGVjdF9yYXRpbyA9IDAuOCkNCg0KIyAyeDMgZ3JpZCAoaG9yaXpvbnRhbCBsYXlvdXQpDQoobnV1a19lZmZlY3RzaXplX3Bsb3RfZ3JpZF9ob3IgPC0gcGxvdF9ncmlkKGVmZmVjdF9zaXplX3Bsb3QuQmV0TmFuLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5FbXBOaWcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3Rfc2l6ZV9wbG90LlJob0dybywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdF9zaXplX3Bsb3QuU2FsR2xhLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5WYWNVbGksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImEpIiwgImIpIiwgImMpIiwgImQpIiwgImUpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAyMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfZm9udGZhY2UgPSAicGxhaW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IC0yLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMykpDQoNCiMgc2F2ZSBwbG90DQojIHNhdmVfcGxvdChmaWxlLnBhdGgoIi4uIiwgImZpZ3VyZXMiLCAibnV1a19zaHJ1Yl9kcml2ZXJzX2JldGFiaW5vbV9lZmZlY3Rfc2l6ZV9wYW5lbHNfaG9yLmVwcyIpLA0KIyAgICAgICAgICAgbnV1a19lZmZlY3RzaXplX3Bsb3RfZ3JpZF9ob3IsIGJhc2VfaGVpZ2h0ID0gMTAsIGJhc2VfYXNwZWN0X3JhdGlvID0gMS41KQ0KDQojIDJ4MyBncmlkIHJlZHVjZWQgcHJlZGljdG9yIHRlcm1zDQoobnV1a19yZWR1Y2VkX2VmZmVjdHNpemVfcGxvdF9ncmlkX2hvciA8LSBwbG90X2dyaWQoZWZmZWN0X3NpemVfcGxvdC5CZXROYW4yLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5FbXBOaWcyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5SaG9Hcm8yLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5TYWxHbGEyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0X3NpemVfcGxvdC5WYWNVbGkyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJhKSIsICJiKSIsICJjKSIsICJkKSIsICJlKSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9zaXplID0gMjAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2ZvbnRmYWNlID0gInBsYWluIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAtMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMpKQ0KDQojIHNhdmUgcGxvdA0KIyBzYXZlX3Bsb3QoZmlsZS5wYXRoKCIuLiIsICJmaWd1cmVzIiwgIm51dWtfc2hydWJfZHJpdmVyc19iZXRhYmlub21fcmVkdWNlZF9lZmZlY3Rfc2l6ZV9wYW5lbHNfaG9yLmVwcyIpLA0KIyAgICAgICAgICAgbnV1a19yZWR1Y2VkX2VmZmVjdHNpemVfcGxvdF9ncmlkX2hvciwgYmFzZV9oZWlnaHQgPSAxMCwgYmFzZV9hc3BlY3RfcmF0aW8gPSAxLjUpDQpgYGANCg0KIyMgR3JhcGhzDQojIyMgKkJldHVsYSBuYW5hKiAtIHRlbXBlcmF0dXJlIHZhcmlhYmlsaXR5DQpgYGB7cn0NCg0KIyBDb2VmZmljaWVudHMgZXh0cmFjdGlvbiAtLS0tDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KICAjIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQoNCg0KIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0IDwtIGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCAlPiUgDQoNCiAgc2VsZWN0KHBhcmFtLCBtZWFuLCBzZCwgDQogICAgICAgICBsOTUgPSAiMi41JSIsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCiMgYXNzZW1ibGUgcHJlZGljdGVkIGFuZCBwcmVkaWN0b3IgdmFsdWVzDQpwaGF0cyA8LSBjb2VmZi5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yICU+JSANCiAgDQogICMgZmlsdGVyIGZvciBwcmVkaWN0ZWQgdmFsdWVzDQogIGZpbHRlcihwYXJhbSAlaW4lIGMocGFzdGUwKCJwaGF0X3RlbXBjb250WyIsIHNlcShmcm9tID0gMSwgdG8gPSAxMDApLCAiXSIpKSkgJT4lIA0KICANCiAgIyBhZGQgeGhhdHMgY29sdW1uDQogIG11dGF0ZSh4aGF0cyA9IHNlcShmcm9tID0gbWluKEJldE5hbi50b3QkdGVtcGNvbnRfdHNfMzBDKSwNCiAgICAgICAgICAgICAgICAgICAgIHRvID0gbWF4KEJldE5hbi50b3QkdGVtcGNvbnRfdHNfMzBDKSwNCiAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAxMDApKQ0KDQojIGJhY2stY2VudGVyIGFuZCBiYWNrLXNjYWxlIHByZWRpY3RvciB2YWx1ZXMgKHhoYXRzKQ0KcGhhdHMkdGVtcGNvbnQgPC0gcGhhdHMkeGhhdHMqYXR0cihzY2FsZShCZXROYW4udG90JHRlbXBjb250X3RzXzMwKSwgJ3NjYWxlZDpzY2FsZScpICsgYXR0cihzY2FsZShCZXROYW4udG90JHRlbXBjb250X3RzXzMwKSwgJ3NjYWxlZDpjZW50ZXInKSANCg0KDQojIEdSQVBIDQpnZ3Bsb3QoKSArDQogICMgdGVtcGNvbnQgaXMgbW9kZWxsZWQgYXQgcGxvdGdyb3VwIGxldmVsLCBzbyByZWR1Y2UgYmFzZSBkYXRhIChwb2ludHMgbGF5ZXIpIHRvIHBsb3Rncm91cCBsZXZlbA0KICBnZW9tX3BvaW50KGRhdGEgPSBCZXROYW4udG90ICU+JSBncm91cF9ieShzaXRlX2FsdF9wbG90Z3JvdXBfaWQpICU+JSBzdW1tYXJpc2UodGVtcGNvbnQgPSBtZWFuKHRlbXBjb250X3RzXzMwKSwgY292ZXIgPSBtZWFuKGNvdmVyKSksIA0KICAgICAgICAgICAgIGFlcyh4ID0gdGVtcGNvbnQsIA0KICAgICAgICAgICAgICAgICB5ID0gY292ZXIpLCANCiAgICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aD0wLCBoZWlnaHQ9LjAxKSwNCiAgICAgICAgICAgICBhbHBoYT0wLjUpICsNCiAgDQogICMgZHJhdyBsaW5lIG9mIHByZWRpY3RlZCB2YWx1ZXMNCiAgZ2VvbV9saW5lKGRhdGEgPSBwaGF0cywgDQogICAgICAgICAgICBhZXMoeCA9IHRlbXBjb250LCANCiAgICAgICAgICAgICAgICB5ID0gcGxvZ2lzKG1lYW4pKSwgDQogICAgICAgICAgICBjb2xvdXIgPSAib3JhbmdlIiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIHNpemUgPSAzKSArIA0KICANCiAgIyBkcmF3IHByZWRpY3RlZCA5NSUgQ0kNCiAgZ2VvbV9yaWJib24oZGF0YSA9IHBoYXRzLA0KICAgICAgICAgICAgICBhZXMoeCA9IHRlbXBjb250LCANCiAgICAgICAgICAgICAgICAgIHltaW4gPSBwbG9naXMobDk1KSwgDQogICAgICAgICAgICAgICAgICB5bWF4ID0gcGxvZ2lzKHU5NSkpLA0KICAgICAgICAgICAgICBmaWxsID0gIm9yYW5nZSIsDQogICAgICAgICAgICAgIGFscGhhID0gMC4yKSArDQogIA0KICAjIGRlZmluZSBhcHBlYXJhbmNlDQogIGxhYnMoeCA9ICJhbm51YWwgdGVtcGVyYXR1cmUgdmFyaWFiaWxpdHkgW8KwQ10iLA0KICAgICAgIHkgPSAicmVsLiBuby4gaGl0cyBwZXIgcGxvdCIpICsgDQogIHRoZW1lX2J3KCkNCg0KIyBvbGQgdmVyc2lvbiAtLS0NCnVuaXF1ZS50ZW1wY29udCA8LSBzZXEobWluKEJldE5hbi50b3QkdGVtcGNvbnRfdHNfMzBDKSwgbWF4KEJldE5hbi50b3QkdGVtcGNvbnRfdHNfMzBDKSwgYnk9MC4wMikgDQoNCnByZWRzLnRlbXBjb250LkJldE5hbiA8LSBhcnJheShkaW09YyhsZW5ndGgodW5pcXVlLnRlbXBjb250KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyhtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiRCVUdTb3V0cHV0JHNpbXMubGlzdCRiX3Bsb3Rncm91cCkpKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgodW5pcXVlLnRlbXBjb250KSl7DQogIHByZWRzLnRlbXBjb250LkJldE5hbltpLF0gPC0gcGxvZ2lzKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yJEJVR1NvdXRwdXQkc2ltcy5saXN0JGIudGVtcGNvbnQueFssMV0qdW5pcXVlLnRlbXBjb250W2ldICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiRCVUdTb3V0cHV0JHNpbXMubGlzdCRiLnRlbXBjb250LngyWywxXSoodW5pcXVlLnRlbXBjb250W2ldXjIpKQ0KfQ0KDQojICMgcHJlZHMuY29udGluZW50MWJpb21lMiA8LSBhcnJheShkaW09YyhsZW5ndGgodW5pcXVlLnRlbXBjb250KSwNCiMgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiRCVUdTb3V0cHV0JHNpbXMubGlzdCRiMW1lYW5Gb3Jlc3RbLDFdKSkpDQojICMgDQojICMgZm9yIChpIGluIDE6bGVuZ3RoKHVuaXF1ZS50ZW1wY29udCkpew0KIyAjICAgcHJlZHMuY29udGluZW50MWJpb21lMltpLF0gPC0gcGxvZ2lzKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5CZXROYW4yJEJVR1NvdXRwdXQkc2ltcy5saXN0JGIxbWVhblNhdmFubmEgKyBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiRCVUdTb3V0cHV0JHNpbXMubGlzdCRicmFpbi54WywyXSp1bmlxdWUudGVtcGNvbnRbaV0gKyBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuQmV0TmFuMiRCVUdTb3V0cHV0JHNpbXMubGlzdCRicmFpbi54MlssMl0qKHVuaXF1ZS50ZW1wY29udFtpXV4yKSl9DQoNCg0KIyAjIGNvbnRpbmVudHByZWRzIDwtIGFycmF5KGMocHJlZHMuY29udGluZW50MWJpb21lMSxwcmVkcy5jb250aW5lbnQxYmlvbWUyKSwgZGltPWMobGVuZ3RoKHVuaXF1ZS50ZW1wY29udCksIG5jb2wocHJlZHMuY29udGluZW50MWJpb21lMSksMikpDQoNCnByZWRzLnRlbXBjb250LkJldE5hblsxOjEwLDE6MTBdICMgW3RlbXBjb250LHNpbXNdDQoNCnF1YW50aWxlcy50ZW1wY29udC5CZXROYW4gPC0gYXJyYXkoTkEsIGRpbT1jKGxlbmd0aCh1bmlxdWUudGVtcGNvbnQpLDUpKQ0KDQoNCmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWUudGVtcGNvbnQpKXsjdGVtcGNvbnQNCiAgI2k8LTENCiAgICBxdWFudGlsZXMudGVtcGNvbnQuQmV0TmFuW2ksXTwtcXVhbnRpbGUocHJlZHMudGVtcGNvbnQuQmV0TmFuW2ksXSwgYygwLjAyNSwgMC4yNSwgMC41LCAwLjk1LCAwLjk3NSkpDQp9DQoNCnF1YW50aWxlcy50ZW1wY29udC5CZXROYW5bMTo1LDE6NV0NCg0KcHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuIDwtIGRhdGEuZnJhbWUoZXhwYW5kLmdyaWQodGVtcGNvbnRfdHNfMzBDPWModW5pcXVlLnRlbXBjb250KSkpDQpwcmVkc21hdHJpeC50ZW1wY29udC5CZXROYW4kbDk1Q0k8LXJlcChOQSwgbnJvdyhwcmVkc21hdHJpeC50ZW1wY29udC5CZXROYW4pKQ0KcHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuJGw5MENJPC1yZXAoTkEsIG5yb3cocHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuKSkNCnByZWRzbWF0cml4LnRlbXBjb250LkJldE5hbiRtZWQ8LXJlcChOQSwgbnJvdyhwcmVkc21hdHJpeC50ZW1wY29udC5CZXROYW4pKQ0KcHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuJHU5MENJPC1yZXAoTkEsIG5yb3cocHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuKSkNCnByZWRzbWF0cml4LnRlbXBjb250LkJldE5hbiR1OTVDSTwtcmVwKE5BLCBucm93KHByZWRzbWF0cml4LnRlbXBjb250LkJldE5hbikpIA0KDQpoZWFkKHByZWRzbWF0cml4LnRlbXBjb250LkJldE5hbikNCg0KIyAjIHJhaW5mYWxsc2VxPC1yZXAoMTpsZW5ndGgodW5pcXVlLnRlbXBjb250KSxlYWNoPTIpDQoNCmZvciAoaSBpbiAxOm5yb3cocHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuKSl7DQogIHByZWRzbWF0cml4LnRlbXBjb250LkJldE5hbltpLGMoMjo2KV0gPC0gcXVhbnRpbGVzLnRlbXBjb250LkJldE5hbltpLF0NCn0NCg0KcHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuJHRlbXBjb250IDwtIGF0dHIoc2NhbGUoQmV0TmFuLnRvdCR0ZW1wY29udF90c18zMCksICdzY2FsZWQ6c2NhbGUnKSArIGF0dHIoc2NhbGUoQmV0TmFuLnRvdCR0ZW1wY29udF90c18zMCksICdzY2FsZWQ6Y2VudGVyJykNCg0KZ2dwbG90KCkgKw0KICAjIHRlbXBjb250IGlzIG1vZGVsbGVkIGF0IHBsb3Rncm91cCBsZXZlbCwgc28gcmVkdWNlIGJhc2UgZGF0YSAocG9pbnRzIGxheWVyKSB0byBwbG90Z3JvdXAgbGV2ZWwNCiAgZ2VvbV9wb2ludChkYXRhID0gQmV0TmFuLnRvdCAlPiUgZ3JvdXBfYnkoc2l0ZV9hbHRfcGxvdGdyb3VwX2lkKSAlPiUgc3VtbWFyaXNlKHRlbXBjb250ID0gbWVhbih0ZW1wY29udF90c18zMCksIGNvdmVyID0gbWVhbihjb3ZlcikpLCANCiAgICAgICAgICAgICBhZXMoeCA9IHRlbXBjb250LCANCiAgICAgICAgICAgICAgICAgeSA9IGNvdmVyKSwgDQogICAgICAgICAgICAgc2l6ZSA9IDIsDQogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGg9MCwgaGVpZ2h0PS4wMSksDQogICAgICAgICAgICAgYWxwaGE9MC41KSArDQogIA0KICAjIGRyYXcgbGluZSBvZiBwcmVkaWN0ZWQgdmFsdWVzDQogIGdlb21fbGluZShkYXRhID0gcHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuLCANCiAgICAgICAgICAgIGFlcyh4ID0gdGVtcGNvbnQsIA0KICAgICAgICAgICAgICAgIHkgPSBtZWQpLCANCiAgICAgICAgICAgIGNvbG91ciA9ICJvcmFuZ2UiLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgc2l6ZSA9IDMpICsgDQogICMgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyZWVuIiwib3JhbmdlIiwiZGFya2dyZWVuIiwib3JhbmdlIiksbmFtZT0iQmlvbWUiKSArDQogIA0KICAjIGRyYXcgcHJlZGljdGVkIDk1JSBDSQ0KICBnZW9tX3JpYmJvbihkYXRhID0gcHJlZHNtYXRyaXgudGVtcGNvbnQuQmV0TmFuLA0KICAgICAgICAgICAgICAgIGFlcyh4ID0gdGVtcGNvbnQsIA0KICAgICAgICAgICAgICAgICAgeW1pbiA9IGw5NUNJLCANCiAgICAgICAgICAgICAgICAgIHltYXggPSB1OTVDSSksDQogICAgICAgICAgICAgIGZpbGwgPSAib3JhbmdlIiwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgDQogICMgZHJhdyBwcmVkaWN0ZWQgOTAlIENJDQogIGdlb21fcmliYm9uKGRhdGEgPSBwcmVkc21hdHJpeC50ZW1wY29udC5CZXROYW4sDQogICAgICAgICAgICAgICAgYWVzKHggPSB0ZW1wY29udCwgDQogICAgICAgICAgICAgICAgICB5bWluID0gbDkwQ0ksIA0KICAgICAgICAgICAgICAgICAgeW1heCA9IHU5MENJKSwNCiAgICAgICAgICAgICAgZmlsbCA9ICJvcmFuZ2UiLA0KICAgICAgICAgICAgICBhbHBoYSA9IDAuNCkgKw0KICAjIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JlZW4iLCJvcmFuZ2UiKSxuYW1lPSJCaW9tZSIpICsNCiAgbGFicyh4ID0gImFubnVhbCB0ZW1wZXJhdHVyZSB2YXJpYWJpbGl0eSBbwrBDXSIsDQogICAgICAgeSA9ICJyZWwuIG5vLiBoaXRzIHBlciBwbG90IikgKyANCiAgdGhlbWVfYncoKQ0KYGBgDQoNCiMjIyAqU2FsaXggZ2xhdWNhKiAtIGNvbXBldGl0aW9uDQpgYGB7cn0NCg0KdW5pcXVlLmNvbXBldCA8LSBzZXEobWluKFNhbEdsYS50b3QkY29tcGV0QyksIG1heChTYWxHbGEudG90JGNvbXBldEMpLCBieSA9IDAuMDIpIA0KDQpwcmVkcy5jb21wZXQuU2FsR2xhIDwtIGFycmF5KGRpbT1jKGxlbmd0aCh1bmlxdWUuY29tcGV0KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyhtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMiRCVUdTb3V0cHV0JHNpbXMubGlzdCRiX3Bsb3Rncm91cCkpKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgodW5pcXVlLmNvbXBldCkpew0KICBwcmVkcy5jb21wZXQuU2FsR2xhW2ksXSA8LSBwbG9naXMobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIkQlVHU291dHB1dCRzaW1zLmxpc3QkYi5jb21wZXRbLDFdKnVuaXF1ZS5jb21wZXRbaV0pDQp9DQoNCiMgIyBwcmVkcy5jb250aW5lbnQxYmlvbWUyIDwtIGFycmF5KGRpbT1jKGxlbmd0aCh1bmlxdWUuY29tcGV0KSwgDQojICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIkQlVHU291dHB1dCRzaW1zLmxpc3QkYjFtZWFuRm9yZXN0WywxXSkpKQ0KIyAjIA0KIyAjIGZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWUuY29tcGV0KSl7DQojICMgICBwcmVkcy5jb250aW5lbnQxYmlvbWUyW2ksXSA8LSBwbG9naXMobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIkQlVHU291dHB1dCRzaW1zLmxpc3QkYjFtZWFuU2F2YW5uYSArIG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyJEJVR1NvdXRwdXQkc2ltcy5saXN0JGJyYWluLnhbLDJdKnVuaXF1ZS5jb21wZXRbaV0gKyBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMiRCVUdTb3V0cHV0JHNpbXMubGlzdCRicmFpbi54MlssMl0qKHVuaXF1ZS5jb21wZXRbaV1eMikpfQ0KDQoNCiMgIyBjb250aW5lbnRwcmVkcyA8LSBhcnJheShjKHByZWRzLmNvbnRpbmVudDFiaW9tZTEscHJlZHMuY29udGluZW50MWJpb21lMiksIGRpbT1jKGxlbmd0aCh1bmlxdWUuY29tcGV0KSwgbmNvbChwcmVkcy5jb250aW5lbnQxYmlvbWUxKSwyKSkNCg0KcHJlZHMuY29tcGV0LlNhbEdsYVsxOjEwLDE6MTBdICMgW2NvbXBldCxzaW1zXQ0KDQpxdWFudGlsZXMuY29tcGV0LlNhbEdsYSA8LSBhcnJheShOQSwgZGltPWMobGVuZ3RoKHVuaXF1ZS5jb21wZXQpLDUpKQ0KDQoNCmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWUuY29tcGV0KSl7I2NvbXBldA0KICAjaTwtMQ0KICAgIHF1YW50aWxlcy5jb21wZXQuU2FsR2xhW2ksXTwtcXVhbnRpbGUocHJlZHMuY29tcGV0LlNhbEdsYVtpLF0sIGMoMC4wMjUsIDAuMjUsIDAuNSwgMC45NSwgMC45NzUpKQ0KfQ0KDQpxdWFudGlsZXMuY29tcGV0LlNhbEdsYVsxOjUsMTo1XQ0KDQpwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhIDwtIGRhdGEuZnJhbWUoZXhwYW5kLmdyaWQoY29tcGV0Qz1jKHVuaXF1ZS5jb21wZXQpKSkNCnByZWRzbWF0cml4LmNvbXBldC5TYWxHbGEkbDk1Q0k8LXJlcChOQSwgbnJvdyhwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhKSkNCnByZWRzbWF0cml4LmNvbXBldC5TYWxHbGEkbDkwQ0k8LXJlcChOQSwgbnJvdyhwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhKSkNCnByZWRzbWF0cml4LmNvbXBldC5TYWxHbGEkbWVkPC1yZXAoTkEsIG5yb3cocHJlZHNtYXRyaXguY29tcGV0LlNhbEdsYSkpDQpwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhJHU5MENJPC1yZXAoTkEsIG5yb3cocHJlZHNtYXRyaXguY29tcGV0LlNhbEdsYSkpDQpwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhJHU5NUNJPC1yZXAoTkEsIG5yb3cocHJlZHNtYXRyaXguY29tcGV0LlNhbEdsYSkpIA0KDQpoZWFkKHByZWRzbWF0cml4LmNvbXBldC5TYWxHbGEpDQoNCiMgIyByYWluZmFsbHNlcTwtcmVwKDE6bGVuZ3RoKHVuaXF1ZS5jb21wZXQpLGVhY2g9MikNCg0KZm9yIChpIGluIDE6bnJvdyhwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhKSl7DQogIHByZWRzbWF0cml4LmNvbXBldC5TYWxHbGFbaSxjKDI6NildIDwtIHF1YW50aWxlcy5jb21wZXQuU2FsR2xhW2ksXQ0KfQ0KDQpwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhJGNvbXBldCA8LSBwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhJGNvbXBldEMgKyBhdHRyKHNjYWxlKFNhbEdsYS50b3QkY29tcGV0KSwgJ3NjYWxlZDpjZW50ZXInKQ0KDQoocHJlZF9wbG90LmNvbXBldC5TYWxHbGEgPC0gZ2dwbG90KCkgKw0KICAjIGNvbXBldGl0aW9uIGlzIG1vZGVsZWQgb24gcGxvdCBsZXZlbCwgc28gdXNlIGlucHV0IGRhdGEgYXMgaXMNCiAgZ2VvbV9wb2ludChkYXRhID0gU2FsR2xhLnRvdCwgDQogICAgICAgICAgICAgYWVzKHggPSBjb21wZXQsIA0KICAgICAgICAgICAgICAgICB5ID0gY292ZXIpLCANCiAgICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aD0wLCBoZWlnaHQ9LjAxKSwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICANCiAgIyBwbG90IGxpbmUgb2YgcHJlZGljdGVkIG1lZGlhbiB2YWx1ZXMNCiAgZ2VvbV9saW5lKGRhdGEgPSBwcmVkc21hdHJpeC5jb21wZXQuU2FsR2xhLCANCiAgICAgICAgICAgIGFlcyh4ID0gY29tcGV0LCANCiAgICAgICAgICAgICAgICB5ID0gbWVkKSwgDQogICAgICAgICAgICBjb2xvdXIgPSAib3JhbmdlIiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIHNpemUgPSAzKSArIA0KICAjIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoImRhcmtncmVlbiIsIm9yYW5nZSIsImRhcmtncmVlbiIsIm9yYW5nZSIpLG5hbWU9IkJpb21lIikgKw0KICANCiAgIyBwbG90IHByZWRpY3RlZCA5NSUgQ0kNCiAgZ2VvbV9yaWJib24oZGF0YSA9IHByZWRzbWF0cml4LmNvbXBldC5TYWxHbGEsDQogICAgICAgICAgICAgICAgYWVzKHggPSBjb21wZXQsIA0KICAgICAgICAgICAgICAgICAgeW1pbiA9IGw5NUNJLCANCiAgICAgICAgICAgICAgICAgIHltYXggPSB1OTVDSSksDQogICAgICAgICAgICAgIGZpbGwgPSAib3JhbmdlIiwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgIyBwbG90IHByZWRpY3RlZCA5MCUgQ0kNCiAgZ2VvbV9yaWJib24oZGF0YSA9IHByZWRzbWF0cml4LmNvbXBldC5TYWxHbGEsDQogICAgICAgICAgICAgICAgYWVzKHggPSBjb21wZXQsIA0KICAgICAgICAgICAgICAgICAgeW1pbiA9IGw5MENJLCANCiAgICAgICAgICAgICAgICAgIHltYXggPSB1OTBDSSksDQogICAgICAgICAgICAgIGZpbGwgPSAib3JhbmdlIiwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjQpICsNCiAgIyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyZWVuIiwib3JhbmdlIiksbmFtZT0iQmlvbWUiKSArDQogIGxhYnMoeCA9ICJzdW1tZWQgYWJ1bmRhbmNlIG9mIHRhbGxlci1ncm93aW5nIHNwZWNpZXMgcGVyIHBsb3QiLA0KICAgICAgIHkgPSAicmVsLiBuby4gaGl0cyBwZXIgcGxvdCIpICsgDQogIHRoZW1lX2J3KCkpDQpgYGANCmxvb2tzIHdlaXJkOyBwcmVkaWN0aW9uIGRvZXMgbm90IHJlbGF0ZSB0byBkYXRhIHBvaW50cyBpbiB4IG9yIHkgcmFuZ2UuIA0KDQoNCiMjIENoZWNrIHByZWRpY3RlZCB2YWx1ZXMNCg0KTGV0J3MgcnVuIGFub3RoZXIgbW9kZWwgd2l0aCBzb21lIGRlcml2ZWQgdmFsdWVzIHRvIHNlZSBpZiB3ZSBnZXQgdGhlIHNhbWUgbnVtYmVycyBvdXQgYXMgdGhlIHdheSB3ZSBoYXZlIGV4dHJhY3RlZCB0aGVtIGFib3ZlIChpLmUuLCBieSBzY2FsaW5nIGJhY2spLiBUaGF0IHdpbGwgdGVsbCB1cyB3aGV0aGVyIGl0J3MgYSBwcm9ibGVtIHdpdGggdGhlIGJhY2stc2NhbGluZyBvciBhIG1vcmUgZnVuZGFtZW50YWwgaXNzdWUuDQoNCmBgYHtyfQ0KIyBhc3NlbWJsZSBkYXRhOiBTYWxHbGEgYXMgZXhhbXBsZSAtLS0tDQpzaHJ1Yl9ncmFkaWVudF9qYWdzLlNhbEdsYS54aGF0LmRhdGEgPC0gbGlzdCgNCiAgDQogICMgcGxvdCBsZXZlbCBwcmVkaWN0b3JzLCBmb3IgZGlzY3JldGUuLi4NCiAgY292LmRpcyA9IFNhbEdsYS5kaXMkY292ZXIsDQogIHBsb3Rncm91cC5kaXMgPSBTYWxHbGEuZGlzJHBsb3Rncm91cC5OVU0sICNBQiBhZGRlZCB0aGlzDQogICMgaXNvY2xpbmUuZGlzID0gU2FsR2xhLmRpcyRzaXRlX2FsdC5OVU0sDQogICMgaW5jbGluX2Rvd24uZGlzID0gU2FsR2xhLmRpcyRpbmNsaW5fZG93bkMsDQogIHNyaS5kaXMgPSBTYWxHbGEuZGlzJHNyaUMsDQogIHRyaS5kaXMgPSBTYWxHbGEuZGlzJHRyaUMsDQogIHR3aS5kaXMgPSBTYWxHbGEuZGlzJHR3aUMsDQogIGNvbXBldC5kaXMgPSBTYWxHbGEuZGlzJGNvbXBldEMsDQogIE5fZGlzY3JldGUgPSBucm93KFNhbEdsYS5kaXMpLA0KICANCiAgIyAuLi5hbmQgY29udGludW91cyBwYXJ0IG9mIHRoZSBkYXRhDQogIGNvdi5jb250ID0gU2FsR2xhLmNvbnQkY292ZXIsDQogIHBsb3Rncm91cC5jb250ID0gU2FsR2xhLmNvbnQkcGxvdGdyb3VwLk5VTSwgI0FCIGFkZGVkIHRoaXMNCiAgIyBpc29jbGluZS5jb250ID0gU2FsR2xhLmNvbnQkc2l0ZV9hbHQuTlVNLA0KICAjIGluY2xpbl9kb3duLmNvbnQgPSBTYWxHbGEuY29udCRpbmNsaW5fZG93bkMsDQogIHNyaS5jb250ID0gU2FsR2xhLmNvbnQkc3JpQywNCiAgdHJpLmNvbnQgPSBTYWxHbGEuY29udCR0cmlDLA0KICB0d2kuY29udCA9IFNhbEdsYS5jb250JHR3aUMsDQogIGNvbXBldC5jb250ID0gU2FsR2xhLmNvbnQkY29tcGV0QywNCiAgTl9jb250ID0gbnJvdyhTYWxHbGEuY29udCksDQogIA0KICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycw0KICB0ZW1wamphLnRvdCA9IFNhbEdsYS50b3QkdGVtcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0sICMgb25lIHZhbHVlIHBlciB0WHBnDQogICMgdGVtcG1heC50b3QgPSBTYWxHbGEudG90JHRlbXBtYXhfdHNfMzBDWyFkdXBsaWNhdGVkKFNhbEdsYS50b3QkcGxvdGdyb3VwLk5VTSldLA0KICAjIHRlbXBtaW4udG90ID0gU2FsR2xhLnRvdCR0ZW1wbWluX3RzXzMwQ1shZHVwbGljYXRlZChTYWxHbGEudG90JHBsb3Rncm91cC5OVU0pXSwNCiAgdGVtcGNvbnQudG90ID0gU2FsR2xhLnRvdCR0ZW1wY29udF90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogIHByZWNpcGpqYS50b3QgPSBTYWxHbGEudG90JHByZWNpcGpqYV90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0sDQogICMgcHJlY2lwamZtYW0udG90ID0gU2FsR2xhLnRvdCRwcmVjaXBqZm1hbV90c18zMENbIWR1cGxpY2F0ZWQoU2FsR2xhLnRvdCRwbG90Z3JvdXAuTlVNKV0NCiAgTl9wbG90Z3JvdXBzID0gbGVuZ3RoKHVuaXF1ZShTYWxHbGEudG90JHNpdGVfYWx0X3Bsb3Rncm91cF9pZCkpLA0KICANCiAgeGhhdCA9IHNlcShmcm9tID0gbWluKFNhbEdsYS50b3QkdGVtcGNvbnRfdHNfMzBDKSwgdG8gPSBtYXgoU2FsR2xhLnRvdCR0ZW1wY29udF90c18zMEMpLCBsZW5ndGgub3V0ID0gMTAwKSwNCiAgTnhoYXQgPSAxMDANCiAgIyAjIHNpdGUvYWx0IGxldmVsIHByZWRpY3RvcnMNCiAgIyBhbHQudG90ID0gU2FsR2xhLnRvdCRhbHRDWyFkdXBsaWNhdGVkKFNhbEdsYS50b3Qkc2l0ZV9hbHQuTlVNKV0sDQogICMgTl9pc29jbGluZXMgPSBsZW5ndGgodW5pcXVlKFNhbEdsYS50b3Qkc2l0ZV9hbHRfaWQpKQ0KKQ0Kc3RyKHNocnViX2dyYWRpZW50X2phZ3MuU2FsR2xhLnhoYXQuZGF0YSkNCmBgYA0KDQpXZSdsbCBhZGQgc29tZSBwcmVkaWN0ZWQgdmFsdWVzIChwaGF0KSB0byB0aGUgbW9kZWw6DQoNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCndyaXRlKCINCiAgDQogIG1vZGVsew0KICAgIA0KICAgICMgcHJpb3JzDQogICAgICANCiAgICAgIGludGVyY2VwdCB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIA0KICAgICAgYi5jb21wZXQgfiBkbm9ybSgwLCAwLjAwMDEpDQogICAgICBiLnNyaSB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgICMgYi5pbmNsaW5fZG93biB+IGRub3JtKDAsIDAuMDAwMSkNCiAgICAgIGIudHJpIH4gZG5vcm0oMCwgMC4wMDAxKQ0KICAgICAgYi50d2kgfiBkbm9ybSgwLCAwLjAwMDEpDQoNCiAgICAgIHNpZ21hLnBsb3Rncm91cCB+IGR1bmlmKDAsMTAwKQ0KICAgICAgdGF1LnBsb3Rncm91cCA8LSAxLyhzaWdtYS5wbG90Z3JvdXAgKiBzaWdtYS5wbG90Z3JvdXApDQogICAgICANCiAgICAgICMgc2lnbWEuaXNvY2xpbmUgfiBkdW5pZigwLDEwMCkNCiAgICAgICMgdGF1Lmlzb2NsaW5lIDwtIDEvKHNpZ21hLmlzb2NsaW5lICogc2lnbWEuaXNvY2xpbmUpDQogICAgICAjIA0KICAgICAgIyBiLmFsdC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIuYWx0LngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnRlbXBqamEueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgYi50ZW1wamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcG1heC54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIudGVtcG1heC54MiB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBtaW4ueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBtaW4ueDIgfiBkbm9ybSgwLCAwLjAwMSkNCiAgICAgIGIudGVtcGNvbnQueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnRlbXBjb250LngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICBiLnByZWNpcGpqYS54IH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIucHJlY2lwamphLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICAjIGIucHJlY2lwamZtYW0ueCB+IGRub3JtKDAsIDAuMDAxKQ0KICAgICAgIyBiLnByZWNpcGpmbWFtLngyIH4gZG5vcm0oMCwgMC4wMDEpDQogICAgICANCiAgICAgIHBoaSB+IGRnYW1tYSgwLjEsIDAuMSkNCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBkaXNjcmV0ZSBwYXJ0DQoNCiAgICAgIGZvciAoaSBpbiAxOk5fZGlzY3JldGUpeyANCiAgICAgICAgY292LmRpc1tpXSB+IGRiZXJuKG11W2ldKQ0KICAgICAgICBsb2dpdChtdVtpXSkgPC0gYl9wbG90Z3JvdXBbcGxvdGdyb3VwLmRpc1tpXV0gKyAjQUIgYWRkZWQgdGhpcywgfj0gcmFuZG9tIGVmZmVjdCBvZiBwbG90IGdyb3VwDQogICAgICAgICAgICAgICAgICAgICAgICAjIGJfaXNvY2xpbmVbaXNvY2xpbmUuZGlzW2ldXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi5pbmNsaW5fZG93biAqIGluY2xpbl9kb3duLmRpc1tpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnR3aSAqIHR3aS5kaXNbaV0gKyANCiAgICAgICAgICAgICAgICAgICAgICAgIGIuc3JpICogc3JpLmRpc1tpXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5kaXNbaV0NCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgIyBMSUtFTElIT09EIGZvciBjb250aW51b3VzIHBhcnQNCg0KICAgICAgZm9yIChqIGluIDE6Tl9jb250KXsNCiAgICAgICAgY292LmNvbnRbal0gfiBkYmV0YShwW2pdLCBxW2pdKQ0KICAgICAgICBwW2pdIDwtIG11MltqXSAqIHBoaQ0KICAgICAgICBxW2pdIDwtICgxIC0gbXUyW2pdKSAqIHBoaQ0KICAgICAgICBsb2dpdChtdTJbal0pIDwtIGJfcGxvdGdyb3VwW3Bsb3Rncm91cC5jb250W2pdXSArICNBQiBhZGRlZCB0aGlzLCB+PSByYW5kb20gZWZmZWN0IG9mIHBsb3QgZ3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgICMgYl9pc29jbGluZVtpc29jbGluZS5jb250W2pdXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLmNvbXBldCAqIGNvbXBldC5jb250W2pdICsNCiAgICAgICAgICAgICAgICAgICAgICAgICMgYi5pbmNsaW5fZG93biAqIGluY2xpbl9kb3duLmNvbnRbal0gKw0KICAgICAgICAgICAgICAgICAgICAgICAgYi50d2kgKiB0d2kuY29udFtqXSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgYi5zcmkgKiBzcmkuY29udFtqXSArDQogICAgICAgICAgICAgICAgICAgICAgICBiLnRyaSAqIHRyaS5jb250W2pdDQogICAgICB9DQoNCg0KICAgICAgZm9yIChrIGluIDE6Tl9wbG90Z3JvdXBzKXsgIyBsZW5ndGggb2YgdG90YWwgcGxvdGdyb3Vwcw0KICAgICAgICBiX3Bsb3Rncm91cFtrXSB+IGRub3JtKG11LnBsb3Rncm91cFtrXSx0YXUucGxvdGdyb3VwKQ0KICAgICAgICBtdS5wbG90Z3JvdXBba10gPC0gaW50ZXJjZXB0ICsgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIHBsb3QgZ3JvdXAgbGV2ZWwgcHJlZGljdG9ycywgbGluZWFyIGFuZCBxdWFkcmF0aWMgdGVybQ0KICAgICAgICAgICAgICAgICAgICBiLnRlbXBqamEueCAqIHRlbXBqamEudG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wamphLngyICogKHRlbXBqamEudG90W2tdXjIpICsgDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wbWF4LnggKiB0ZW1wbWF4LnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcG1heC54MiAqICh0ZW1wbWF4LnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgICMgYi50ZW1wbWluLnggKiB0ZW1wbWluLnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcG1pbi54MiAqICh0ZW1wbWluLnRvdFtrXV4yKSArDQogICAgICAgICAgICAgICAgICAgIGIudGVtcGNvbnQueCAqIHRlbXBjb250LnRvdFtrXSArIA0KICAgICAgICAgICAgICAgICAgICAjIGIudGVtcGNvbnQueDIgKiAodGVtcGNvbnQudG90W2tdXjIpICsNCiAgICAgICAgICAgICAgICAgICAgYi5wcmVjaXBqamEueCAqIHByZWNpcGpqYS50b3Rba10gIyArIA0KICAgICAgICAgICAgICAgICAgICAjIGIucHJlY2lwamphLngyICogKHByZWNpcGpqYS50b3Rba11eMikgIyArDQogICAgICAgICAgICAgICAgICAgICMgYi5wcmVjaXBqZm1hbS54ICogcHJlY2lwamZtYW0udG90W2tdICsgDQogICAgICAgICAgICAgICAgICAgICMgYi5wcmVjaXBqZm1hbS54MiAqIChwcmVjaXBqZm1hbS50b3Rba11eMikNCiAgICAgIH0NCiAgICAgIA0KICAgICAgDQogICAgICAjIGZvciAobCBpbiAxOk5faXNvY2xpbmVzKXsgI2xlbmd0aCBvZiB0b3RhbCBpc29jbGluZXMNCiAgICAgICMgICBiX2lzb2NsaW5lW2xdIH4gZG5vcm0obXUuaXNvY2xpbmVbbF0sdGF1Lmlzb2NsaW5lKQ0KICAgICAgIyAgIG11Lmlzb2NsaW5lW2xdIDwtIGludGVyY2VwdCArIA0KICAgICAgIyAgIA0KICAgICAgIyAgICAgICAgICAgICAgICMgaXNvY2xpbmUtbGV2ZWwgcHJlZGljdG9yDQogICAgICAjICAgICAgICAgICAgICAgYi5hbHQueCAqIGFsdC50b3RbbF0NCiAgICAgICMgfQ0KDQogICAgICANCiAgICAgICMgYWRkIHByZWRpY3RlZCB2YWx1ZXMgKGRlcml2ZWQgcXVhbnRpdGllcykNCiAgICAgIGZvciAobSBpbiAxOk54aGF0KXsNCiAgICAgICAgcGhhdFttXSA8LSBpbnRlcmNlcHQgKyBiLnRlbXBjb250LnggKiB4aGF0W21dDQogICAgICB9DQogICAgDQogICAgICB9DQogICIsIGZpbGUucGF0aCgiLi4iLCAibW9kZWxzIiwgInNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdC5qYWdzIikpDQpgYGANCg0KU3BlY2lmeSB0aGUgcGFyYW1ldGVycyB0byBiZSBtb25pdG9yZWQ6DQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQpwYXJhbXNfU2FsR2xhMi54aGF0IDwtIGMoImludGVyY2VwdCIsDQogICAgICAgICAgICAgICAgICAgICMgImIuYWx0LngiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wamphLngiLCAjICJiLnRlbXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAjICJiLnRlbXBtYXgueCIsICJiLnRlbXBtYXgueDIiLA0KICAgICAgICAgICAgICAgICAgICAjICJiLnRlbXBtaW4ueCIsICJiLnRlbXBtaW4ueDIiLA0KICAgICAgICAgICAgICAgICAgICAiYi50ZW1wY29udC54IiwgIyAiYi50ZW1wY29udC54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLnByZWNpcGpqYS54IiwgIyAiYi5wcmVjaXBqamEueDIiLA0KICAgICAgICAgICAgICAgICAgICAjICJiLnByZWNpcGpmbWFtLngiLCAiYi5wcmVjaXBqZm1hbS54MiIsDQogICAgICAgICAgICAgICAgICAgICJiLmNvbXBldCIsIA0KICAgICAgICAgICAgICAgICAgICAjICJiLmluY2xpbl9kb3duIiwNCiAgICAgICAgICAgICAgICAgICAgImIuc3JpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHJpIiwNCiAgICAgICAgICAgICAgICAgICAgImIudHdpIiwNCiAgICAgICAgICAgICAgICAgICAgImJfcGxvdGdyb3VwWzFdIiwiYl9wbG90Z3JvdXBbMl0iLCJiX3Bsb3Rncm91cFszXSIsImJfcGxvdGdyb3VwWzYzXSIsDQogICAgICAgICAgICAgICAgICAgICMgImJfaXNvY2xpbmVbMV0iLCJiX2lzb2NsaW5lWzJdIiwiYl9pc29jbGluZVsyMV0iLA0KICAgICAgICAgICAgICAgICAgICAic2lnbWEucGxvdGdyb3VwIiwNCiAgICAgICAgICAgICAgICAgICAgInBoaSIsDQogICAgICAgICAgICAgICAgICAgICJwaGF0IikNCmBgYA0KDQpSdW4gbW9kZWw6DQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQptb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0IDwtIGphZ3Moc2hydWJfZ3JhZGllbnRfamFncy5TYWxHbGEueGhhdC5kYXRhLCAgICAjIGlucHV0IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0cyA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAjIEpBR1MgdG8gY3JlYXRlIGluaXRpYWwgdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zX1NhbEdsYTIueGhhdCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcGFyYW1ldGVycyB0byBiZSBzYXZlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgIm1vZGVscyIsICJzaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQuamFncyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNoYWlucyA9IDMsICAgICAgICAgICAgICAgICAgICAgICAjIG5vLiBNYXJrb3YgY2hhaW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5pdGVyID0gMTAwMDAsIG4uYnVybmluID0gNzAwMCwgICMgbm8uIGl0ZXJhdGlvbnMgJiBidXJuLWluIGZyYWN0aW9uIHBlciBjaGFpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4udGhpbiA9IDIsICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhpbm5pbmcgcmF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERJQyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICMgZG8gbm90IGNvbXB1dGUgZGV2aWFuY2UsIHBELCBhbmQgRElDDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2luZy5kaXJlY3RvcnkgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9ncmVzcy5iYXIgPSAidGV4dCIpDQoNCiMgcGxvdChtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0KSAjY2hlY2sgY29udmVyZ2VuY2UsIGV0Yy4NCg0KIyBzYXZlKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQsIGZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dF9TYWxHbGEyX3dpdGhfZGVyaXZlZF92YWx1ZXMuUkRhdGEiKSkNCmBgYA0KRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIG1ha2UgZ3JhcGggb2YgZGF0YSBhbmQgcHJlZGljdGlvbiBjdXJ2ZToNCmBgYHtyfQ0KIyBleHRyYWN0IGNvZWZmaWNpZW50cyANCmNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCA8LSBtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0JEJVR1NvdXRwdXQkc3VtbWFyeSAlPiUgDQogIGFzLmRhdGEuZnJhbWUgJT4lIA0KICBzZWxlY3QoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ1JoYXQnKSAlPiUgDQojIGFkZCBpZGVudGlmeWluZyBpbmZvIHRvIGRhdGEgZnJhbWUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwYXJhbSIpDQogICMgbXV0YXRlKHBhcmFtID0gYXMudmVjdG9yKHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQpLCJbW10iLGZpeGVkPUZBTFNFKSwgIlsiLCAxKSkpICMlPiUgcHJpbnQNCg0KIyAjIGFkZCA5MCUgQ0lzDQojIGNpXzkwLlNhbEdsYTIueGhhdCA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxOTUgPSBOQSwgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtID0gTkEpDQojIGZvciAocGFyYW0gaW4gMToobGVuZ3RoKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQkQlVHU291dHB1dCRzaW1zLmxpc3QpKSl7DQojICAgY2lfOTAuU2FsR2xhMi54aGF0W3BhcmFtLDE6Ml0gPC0gcXVhbnRpbGUoZGF0YS5mcmFtZShtb2RlbF9vdXQuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0JEJVR1NvdXRwdXQkc2ltcy5saXN0W3BhcmFtXSlbLDFdLCANCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IGMoMC4wNSwgMC45NSkpDQojICAgY2lfOTAuU2FsR2xhMi54aGF0W3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCiMgfQ0KDQojIGpvaW4gdG8gY29lZmZpY2llbnRzIHRhYmxlDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0ICU+JSANCiAgIyBsZWZ0X2pvaW4oY2lfOTAuU2FsR2xhMi54aGF0LCBieSA9ICJwYXJhbSIpICU+JSANCiAgIyByZW9yZGVyIGFuZCByZW5hbWUgY29scw0KICBzZWxlY3QocGFyYW0sIG1lYW4sIHNkLCANCiAgICAgICAgIGw5NSA9ICIyLjUlIiwNCiAgICAgICAgICMgbDkwID0gcTUsDQogICAgICAgICAjIHU5MCA9IHE5NSwNCiAgICAgICAgIHU5NSA9ICI5Ny41JSIsDQogICAgICAgICBSaGF0KSAjICU+JSBwcmludA0KDQojIGFzc2VtYmxlIHByZWRpY3RlZCBhbmQgcHJlZGljdG9yIHZhbHVlcw0KcGhhdHMgPC0gY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0ICU+JSANCiAgDQogICMgZmlsdGVyIGZvciBwcmVkaWN0ZWQgdmFsdWVzDQogIGZpbHRlcihwYXJhbSAlaW4lIGMocGFzdGUwKCJwaGF0WyIsIHNlcShmcm9tID0gMSwgdG8gPSAxMDApLCAiXSIpKSkgJT4lIA0KICANCiAgIyBhZGQgeGhhdHMgY29sdW1uDQogIG11dGF0ZSh4aGF0cyA9IHNlcShmcm9tID0gbWluKFNhbEdsYS50b3QkdGVtcGNvbnRfdHNfMzBDKSwNCiAgICAgICAgICAgICAgICAgICAgIHRvID0gbWF4KFNhbEdsYS50b3QkdGVtcGNvbnRfdHNfMzBDKSwNCiAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAxMDApKQ0KICANCiMgYmFjay1jZW50ZXIgYW5kIGJhY2stc2NhbGUgcHJlZGljdG9yIHZhbHVlcyAoeGhhdHMpDQoNCnBoYXRzJHRlbXBjb250IDwtIHBoYXRzJHhoYXRzKmF0dHIoc2NhbGUoU2FsR2xhLnRvdCR0ZW1wY29udF90c18zMCksICdzY2FsZWQ6c2NhbGUnKSArIGF0dHIoc2NhbGUoU2FsR2xhLnRvdCR0ZW1wY29udF90c18zMCksICdzY2FsZWQ6Y2VudGVyJykgDQoNCmdncGxvdCgpICsNCiAgIyB0ZW1wY29udCBpcyBtb2RlbGxlZCBhdCBwbG90Z3JvdXAgbGV2ZWwsIHNvIHJlZHVjZSBiYXNlIGRhdGEgKHBvaW50cyBsYXllcikgdG8gcGxvdGdyb3VwIGxldmVsDQogIGdlb21fcG9pbnQoZGF0YSA9IFNhbEdsYS50b3QgJT4lIGdyb3VwX2J5KHNpdGVfYWx0X3Bsb3Rncm91cF9pZCkgJT4lIHN1bW1hcmlzZSh0ZW1wY29udCA9IG1lYW4odGVtcGNvbnRfdHNfMzApLCBjb3ZlciA9IG1lYW4oY292ZXIpKSwgDQogICAgICAgICAgICAgYWVzKHggPSB0ZW1wY29udCwgDQogICAgICAgICAgICAgICAgIHkgPSBjb3ZlciksIA0KICAgICAgICAgICAgIHNpemUgPSAyLA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoPTAsIGhlaWdodD0uMDEpLA0KICAgICAgICAgICAgIGFscGhhPTAuNSkgKw0KICANCiAgIyBkcmF3IGxpbmUgb2YgcHJlZGljdGVkIHZhbHVlcw0KICBnZW9tX2xpbmUoZGF0YSA9IHBoYXRzLCANCiAgICAgICAgICAgIGFlcyh4ID0gdGVtcGNvbnQsIA0KICAgICAgICAgICAgICAgIHkgPSBwbG9naXMobWVhbikpLCANCiAgICAgICAgICAgIGNvbG91ciA9ICJvcmFuZ2UiLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgc2l6ZSA9IDMpICsgDQogICMgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YygiZGFya2dyZWVuIiwib3JhbmdlIiwiZGFya2dyZWVuIiwib3JhbmdlIiksbmFtZT0iQmlvbWUiKSArDQogIA0KICAjIGRyYXcgcHJlZGljdGVkIDk1JSBDSQ0KICBnZW9tX3JpYmJvbihkYXRhID0gcGhhdHMsDQogICAgICAgICAgICAgIGFlcyh4ID0gdGVtcGNvbnQsIA0KICAgICAgICAgICAgICAgICAgeW1pbiA9IHBsb2dpcyhsOTUpLCANCiAgICAgICAgICAgICAgICAgIHltYXggPSBwbG9naXModTk1KSksDQogICAgICAgICAgICAgIGZpbGwgPSAib3JhbmdlIiwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgDQogICMgZHJhdyBwcmVkaWN0ZWQgOTAlIENJDQogICMgZ2VvbV9yaWJib24oZGF0YSA9IHBoYXRzLA0KICAjICAgICAgICAgICAgICAgYWVzKHggPSB0ZW1wY29udCwNCiAgIyAgICAgICAgICAgICAgICAgeW1pbiA9IHBsb2dpcyhsOTApLA0KICAjICAgICAgICAgICAgICAgICB5bWF4ID0gcGxvZ2lzKHU5MCkpLA0KICAjICAgICAgICAgICAgIGZpbGwgPSAib3JhbmdlIiwNCiAgIyAgICAgICAgICAgICBhbHBoYSA9IDAuNCkgKw0KICAjIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJkYXJrZ3JlZW4iLCJvcmFuZ2UiKSxuYW1lPSJCaW9tZSIpICsNCiAgbGFicyh4ID0gImFubnVhbCB0ZW1wZXJhdHVyZSB2YXJpYWJpbGl0eSBbwrBDXSIsDQogICAgICAgeSA9ICJyZWwuIG5vLiBoaXRzIHBlciBwbG90IikgKyANCiAgdGhlbWVfYncoKQ0KYGBgDQoNCkV4dHJhY3QgY29lZmZpY2llbnRzIGFuZCBwbG90IGVmZmVjdCBzaXplczoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojIGxvYWQgbW9kZWwgb2JqZWN0DQpsb2FkKGZpbGUgPSBmaWxlLnBhdGgoIi4uIiwgImRhdGEiLCAicHJvY2Vzc2VkIiwgIm1vZGVsX291dHB1dF9TYWxHbGEyX3dpdGhfZGVyaXZlZF92YWx1ZXMuUkRhdGEiKSkNCiMgZXh0cmFjdCBjb2VmZmljaWVudHMgDQpjb2VmZi5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQgPC0gbW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCRCVUdTb3V0cHV0JHN1bW1hcnkgJT4lIA0KICBhcy5kYXRhLmZyYW1lICU+JSANCiAgc2VsZWN0KCdtZWFuJywnc2QnLCcyLjUlJywnOTcuNSUnLCdSaGF0JykgJT4lIA0KIyBhZGQgaWRlbnRpZnlpbmcgaW5mbyB0byBkYXRhIGZyYW1lDQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW0iKQ0KICAjIG11dGF0ZShwYXJhbSA9IGFzLnZlY3RvcihzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMoY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhKSwiW1tdIixmaXhlZD1GQUxTRSksICJbIiwgMSkpKSAjJT4lIHByaW50DQoNCiMgYWRkIDkwJSBDSXMNCmNpXzkwLlNhbEdsYTIueGhhdCA8LSBkYXRhLmZyYW1lKHE1ID0gTkEsIHE5NSA9IE5BLCBwYXJhbSA9IE5BKQ0KZm9yIChwYXJhbSBpbiAxOihsZW5ndGgobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCRCVUdTb3V0cHV0JHNpbXMubGlzdCktNCkpew0KICBjaV85MC5TYWxHbGEyLnhoYXRbcGFyYW0sMToyXSA8LSBxdWFudGlsZShkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQkQlVHU291dHB1dCRzaW1zLmxpc3RbcGFyYW1dKVssMV0sIHByb2JzID0gYygwLjA1LCAwLjk1KSkNCiAgY2lfOTAuU2FsR2xhMi54aGF0W3BhcmFtLCAzXSA8LSBuYW1lcyhkYXRhLmZyYW1lKG1vZGVsX291dC5zaHJ1Yl9ncmFkaWVudC5TYWxHbGEyLnhoYXQkQlVHU291dHB1dCRzaW1zLmxpc3QpKVtwYXJhbV0NCn0NCg0KIyBqb2luIHRvIGNvZWZmaWNpZW50cyB0YWJsZQ0KY29lZmYuc2hydWJfZ3JhZGllbnQuU2FsR2xhMi54aGF0IDwtIGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCAlPiUgDQogIGxlZnRfam9pbihjaV85MC5TYWxHbGEyLnhoYXQsIGJ5ID0gInBhcmFtIikgJT4lIA0KICAjIHJlb3JkZXIgYW5kIHJlbmFtZSBjb2xzDQogIHNlbGVjdChwYXJhbSwgbWVhbiwgc2QsIA0KICAgICAgICAgbDk1ID0gIjIuNSUiLA0KICAgICAgICAgbDkwID0gcTUsDQogICAgICAgICB1OTAgPSBxOTUsDQogICAgICAgICB1OTUgPSAiOTcuNSUiLA0KICAgICAgICAgUmhhdCkgJT4lIHByaW50DQoNCiMgZWZmZWN0IHNpemUgcGxvdA0KKGVmZmVjdF9zaXplX3Bsb3QuU2FsR2xhMi54aGF0IDwtIG1vZGVsX3Bsb3Rfc2lnX2Z1bmN0aW9uKGNvZWZmLnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCwgdGl0bGVfc3RyaW5nID0gIlNhbGl4IGdsYXVjYSIsIHBsb3Rfd2lkdGggPSAxMSkpDQoNCmBgYA0KDQpleHRyYWN0IHByZWRpY3RlZCB2YWx1ZXM6DQpgYGB7cn0NCiMgZ2V0IHN0YXRpc3RpY2FsIHN1bW1hcnkNCm1vZGVsX3hoYXQub3V0LmRmIDwtIGFzLmRhdGEuZnJhbWUobW9kZWxfb3V0LnNocnViX2dyYWRpZW50LlNhbEdsYTIueGhhdCRCVUdTb3V0cHV0JHN1bW1hcnlbLGMoJ21lYW4nLCdzZCcsJzIuNSUnLCc5Ny41JScsJ24uZWZmJywnUmhhdCcpXSkNCg0KbW9kZWxfeGhhdC5vdXQuZGYkUGFyYW0gPC0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1vZGVsX3hoYXQub3V0LmRmKSwgIltbXSIsIGZpeGVkPUYpLCJbIiwxKQ0KDQpwLm91dCA8LSBtb2RlbF94aGF0Lm91dC5kZlttb2RlbF94aGF0Lm91dC5kZiRQYXJhbT09InBoYXQiLF0NCnAub3V0JHhoYXQgPC0gc2hydWJfZ3JhZGllbnRfamFncy5TYWxHbGEueGhhdC5kYXRhJHhoYXQgI2FkZCB0aGUgIngiIHZhbHVlcyB5b3UgdXNlZCB0byBwcmVkaWN0IHBoYXRzDQpgYGANCg0KcGxvdCBhbG9uZyB3aXRoIGJhY2stc2NhbGVkIHZhbHVlczoNCmBgYHtyfQ0KcHJlZF9wbG90LmNvbXBldC5TYWxHbGEgKw0KICAgZ2VvbV9saW5lKGRhdGEgPSBwLm91dCwgDQogICAgICAgICAgICBhZXMoeCA9IHhoYXQsIA0KICAgICAgICAgICAgICAgIHkgPSBtZWFuKSwgDQogICAgICAgICAgICBjb2xvdXIgPSAiZGFya2dyZWVuIiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBwLm91dCwNCiAgICAgICAgICAgICAgYWVzKHggPSB4aGF0LA0KICAgICAgICAgICAgICAgICAgeW1pbiA9IGAyLjUlYCwgDQogICAgICAgICAgICAgICAgICB5bWF4ID0gYDk3LjUlYCksIA0KICAgICAgICAgICAgICBhbHBoYSA9IDAuMywgDQogICAgICAgICAgICAgIGZpbGwgPSAiZ3JlZW4iKQ0KYGBgDQojIyAtLS0tLS0tLS0tDQoNCiMjIFNhdmUgLyBsb2FkIHdvcmtzcGFjZSBpbWFnZQ0KYGBge3J9DQojIHNhdmUuaW1hZ2UoZmlsZSA9IGZpbGUucGF0aCgiLi4iLCAiZGF0YSIsICJwcm9jZXNzZWQiLCAibnV1a19zaHJ1Yl9kcml2ZXJzX291dHB1dF9ub25zaWd4MnJlbW92ZWQuUkRhdGEiKSkNCg0KIyBsb2FkIHdzIGZvciBmdXJ0aGVyIGFuYWx5c2VzL3Bsb3R0aW5nIGV0YykNCiMgbG9hZChmaWxlLnBhdGgoImRhdGEiLCAicHJvY2Vzc2VkIiwgIm51dWtfc2hydWJfZHJpdmVyc19vdXRwdXRfbm9uc2lneDJyZW1vdmVkLlJEYXRhIikpDQpgYGANCg==